2011-10-19 16 views
7

Tôi vô tình bắt đầu một tập lệnh bash với $! thay vì #! và có hành vi rất lạ. Tôi đang cố gắng tìm ra những gì đã xảy ra.

Nếu bạn cố gắng kịch bản này:

$!/bin/bash 
echo Hello world! 

bạn sẽ nhận được các hành vi sau đây:

$ chmod +x hello 
$ ./hello 
[nothing happens, get prompt back] 
$ exit 
exit 
Hello world! 
$ 

Vì vậy, nó trông như thế này xảy ra:

  1. Một shell bash mới sinh ra.
  2. Khi thoát, phần còn lại của tập lệnh được thực thi.

Có chuyện gì? Mọi thứ xảy ra như thế nào? Nếu không có #!, vỏ sẽ biết sử dụng bash để diễn giải kịch bản như thế nào?

Rõ ràng đây là "thỏa mãn sự tò mò của tôi" thay vì "giải quyết vấn đề của tôi". Googling không mang lại nhiều lợi nhuận, có lẽ vì các truy vấn #!$! không làm cho Google-bot vui vẻ.

Trả lời

9

$ một cái gì đó là một tham số ("biến") mở rộng, nhưng $! trong lợi nhuận đặc biệt là một giá trị không được đặt trong kịch bản của bạn, vì vậy nó mở rộng dưới dạng chuỗi có độ dài bằng không.

Vì vậy kịch bản của bạn, bạn là chính xác, tương đương với:

/bin/bash 
echo Hello world! 

Các shebang magic number là một tính năng cũ của Unix, nhưng vỏ thậm chí còn lớn hơn. Một tệp văn bản với bộ thực thi bit mà hạt nhân không thể thực thi (vì nó không thực sự được biên dịch) được thực thi bởi một vỏ con. Đó là, shell cố tình chạy một shell khác và chuyển tên đường dẫn làm tham số. Đây là cách các lệnh được viết như các kịch bản lệnh shell được thực hiện trước khi shebang được phát minh và nó vẫn còn trong mã.

3

Mở rộng một chút về câu trả lời của @ DigitalRoss :.

Một kịch bản thực thi không có #! trên dòng đầu tiên được thực hiện bởi /bin/sh - ngay cả khi bạn thực hiện nó từ bash (hoặc tcsh). Đây không phải là chức năng vỏ, nó nằm trong hạt nhân. Vì vậy, khi bạn thực thi kịch bản của bạn, nó được thực hiện bởi /bin/sh (có nghĩa là, trên hầu hết các hệ thống, nó sẽ không thể sử dụng các tính năng cụ thể bash), $! mở rộng thành không có gì (vì vỏ đó không có đã khởi chạy bất kỳ quá trình nền nào) và dòng đầu tiên gọi ra một vỏ tương tác/bin/bash. Sau đó, bạn thoát khỏi trình bao tương tác đó và tập lệnh của bạn thực hiện đường dây echo Hello world! và chấm dứt, đưa bạn trở lại trình bao gốc của bạn.Ví dụ: nếu bạn thay đổi echo Hello world! thành echo $BASH_VERSION, bạn sẽ thấy rằng nó không in bất kỳ thứ gì - và nếu bạn nhập history từ vỏ bash tương tác được gọi, nó sẽ không hiển thị bất kỳ thứ gì.

Các vấn đề liên quan