Các #!
dòng được sử dụng trước khi kịch bản được chạy, sau đó bỏ qua khi kịch bản chạy.
Bạn đang hỏi sự khác biệt giữa một dòng shebang và một bình luận thông thường.
Một dòng bắt đầu bằng #!
một nhận xét cũng giống như bất kỳ dòng nào khác bắt đầu bằng #
. Điều này đúng nếu #!
dòng đầu tiên của tệp hoặc bất kỳ nơi nào khác. #!/bin/sh
có tác dụng , nhưng nó không được đọc bởi chính người phiên dịch .
#
không phải là một nhận xét trong tất cả các ngôn ngữ lập trình, nhưng, như bạn biết, đó là một nhận xét trong các shell kiểu Bourne bao gồm sh
và bash
(cũng như hầu hết các shell không theo kiểu Bourne, như csh
). Đó cũng là một nhận xét trong Python . Và đó là một nhận xét trong một loạt các tệp cấu hình hoàn toàn không phải là tập lệnh (như /etc/fstab
).
Giả sử một kịch bản shell bắt đầu bằng #!/bin/sh
. Đó là một nhận xét và trình thông dịch (trình bao) bỏ qua mọi thứ trên dòng sau #
ký tự.
Mục đích của một #!
dòng là không cung cấp thông tin cho người phiên dịch. Mục đích của #!
dòng là báo cho hệ điều hành (hoặc bất kỳ quy trình nào khởi chạy trình thông dịch) những gì sẽ sử dụng làm trình thông dịch .
Nếu bạn gọi tập lệnh dưới dạng tệp thực thi, ví dụ, bằng cách chạy ./script.sh
, hệ thống sẽ hỏi dòng đầu tiên để xem có bắt đầu bằng không #!
, theo sau là 0 hoặc nhiều khoảng trắng, theo sau là lệnh. Nếu có, nó chạy lệnh đó với tên của tập lệnh làm đối số của nó. Trong ví dụ này, nó chạy /bin/sh script.sh
(hoặc, về mặt kỹ thuật, /bin/sh ./script.sh
).
Nếu bạn gọi tập lệnh bằng cách gọi rõ ràng trình thông dịch, #!
dòng không bao giờ được hỏi ý kiến. Vì vậy, nếu bạn chạy sh script.sh
, dòng đầu tiên không có hiệu lực. Nếu script2.sh
dòng đầu tiên là #!/usr/games/nibbles
, chạy sh script2.sh
sẽ không cố mở tập lệnh trong nibbles
(nhưng ./script2.sh
sẽ).
Bạn sẽ nhận thấy rằng trong cả hai trường hợp, phần mở rộng của tập lệnh ( .sh
), nếu nó có phần mở rộng , sẽ ảnh hưởng đến cách nó được chạy. Trong một hệ thống giống như Unix, điều này thường không ảnh hưởng đến cách chạy tập lệnh. Trên một số hệ thống khác, như Windows, #!
dòng shebang có thể bị hệ thống bỏ qua hoàn toàn và tiện ích mở rộng có thể xác định những gì chạy tập lệnh. (Điều này không có nghĩa là bạn cần cung cấp các tiện ích mở rộng tập lệnh của mình, nhưng đó là một trong những lý do tại sao nếu bạn làm như vậy, chúng phải chính xác.)
#!
đã được chọn để phục vụ mục đích này chính xác bởi vì #
bắt đầu một bình luận. Các #!
dòng là đối với hệ thống, chứ không phải phiên dịch, và nó sẽ bị bỏ qua bởi các thông dịch viên.
Dòng Shebang cho Bash Script
Bạn (ban đầu) cho biết bạn sử dụng #!/bin/sh
cho bash
các kịch bản. Bạn chỉ nên làm điều đó nếu tập lệnh không yêu cầu bất kỳ bash
tiện ích mở rộng nào-- sh
cần có khả năng chạy tập lệnh. sh
không phải lúc nào cũng là một liên kết tượng trưng đến bash
. Thông thường, bao gồm trên tất cả các hệ thống Debian và Ubuntu gần đây , sh
là một liên kết tượng trưng đến dash
.
Dòng Shebang cho tập lệnh Python
Bạn cũng đã nói (trong phiên bản đầu tiên của câu hỏi của bạn, trước khi chỉnh sửa) rằng bạn bắt đầu các tập lệnh Python của mình với #!/bin/sh read by the interpretor
. Nếu bạn có nghĩa là theo nghĩa đen, thì bạn chắc chắn nên ngừng làm điều đó. Nếu hello.py
bắt đầu với dòng đó, chạy ./hello.py
thực thi:
/bin/sh read by the interpretor hello.py
/bin/sh
sẽ cố gắng thực thi một tập lệnh được gọi read
(với by the interpretor hello.py
tư cách là đối số của nó), read
sẽ (hy vọng) sẽ không được tìm thấy và tập lệnh Python của bạn sẽ không bao giờ được trình thông dịch Python nhìn thấy.
Nếu bạn đang mắc lỗi này nhưng không gặp phải vấn đề mà tôi đang mô tả, có lẽ bạn đang gọi các đoạn mã Python của mình bằng cách chỉ định rõ ràng trình thông dịch (ví dụ python hello.py
:), khiến dòng đầu tiên bị bỏ qua. Khi bạn phân phối các tập lệnh của mình cho người khác hoặc sử dụng chúng trong một thời gian dài sau đó, có thể không rõ ràng rằng điều này là cần thiết để chúng hoạt động. Tốt nhất là sửa chúng ngay bây giờ. Hoặc ít nhất là loại bỏ hoàn toàn dòng đầu tiên, để khi chúng không chạy với ./
thông báo lỗi sẽ có ý nghĩa.
Đối với các tập lệnh Python, nếu bạn biết trình thông dịch Python ở đâu (hoặc sắp có), bạn có thể viết #!
dòng theo cùng một cách:
#!/usr/bin/python
Hoặc, nếu đó là tập lệnh Python 3, bạn nên chỉ định python3
, vì python
hầu như luôn luôn là Python 2 :
#!/usr/bin/python3
Tuy nhiên, vấn đề là trong khi /bin/sh
được cho là luôn tồn tại và /bin/bash
hầu như luôn tồn tại trên các hệ thống bash
đi kèm với HĐH, Python có thể tồn tại ở nhiều nơi.
Do đó, nhiều lập trình viên Python sử dụng điều này thay thế:
#!/usr/bin/env python
(Hoặc #!/usr/bin/env python3
cho Python 3.)
Điều này làm cho kịch bản dựa vào env
việc ở đúng "chỗ" thay vì dựa vào python
đúng chỗ. Đó là một điều tốt, bởi vì:
env
hầu như luôn luôn nằm trong /usr/bin
.
- Trên hầu hết các hệ thống, bất kỳ hệ thống nào
python
nên chạy tập lệnh của bạn là tập lệnh xuất hiện đầu tiên trong PATH
. Bắt đầu hello.py
với #!/usr/bin/env python
make ./hello.py
run /usr/bin/env python hello.py
, gần như tương đương với chạy python hello.py
.
Lý do bạn không thể sử dụng #!python
là:
- Bạn muốn trình thông dịch được chỉ định sẽ được cung cấp bởi một đường dẫn tuyệt đối (nghĩa là bắt đầu bằng
/
).
- Quá trình gọi sẽ thực hiện
python
trong thư mục hiện tại . Tìm kiếm đường dẫn khi lệnh không chứa dấu gạch chéo là hành vi shell cụ thể.
Đôi khi một Python hoặc kịch bản khác mà không phải là một kịch bản shell sẽ có một dòng công việc bắt đầu với #!/bin/sh ...
nơi ...
là một số mã khác. Điều này đôi khi đúng, bởi vì có một số cách để gọi shell tương thích Bourne ( sh
) với các đối số để làm cho nó gọi trình thông dịch Python. (Một trong những đối số có thể sẽ chứa python
.) Tuy nhiên, đối với hầu hết các mục đích, #!/usr/bin/env python
đơn giản hơn, thanh lịch hơn và có nhiều khả năng hoạt động theo cách bạn muốn.
Dòng Shebang trong các ngôn ngữ khác
Nhiều ngôn ngữ lập trình và kịch bản, và một số định dạng tệp khác, sử dụng #
làm nhận xét. Đối với bất kỳ ai trong số họ, một tệp trong ngôn ngữ có thể được chạy bởi một chương trình lấy nó làm đối số bằng cách chỉ định chương trình trên dòng đầu tiên sau #!
.
Trong một số ngôn ngữ lập trình, #
thông thường không phải là một nhận xét, nhưng trong trường hợp đặc biệt, dòng đầu tiên bị bỏ qua nếu nó bắt đầu bằng #!
. Điều này tạo thuận lợi cho việc sử dụng #!
cú pháp mặc dù #
không đưa ra nhận xét.
Dòng Shebang cho các tệp không chạy dưới dạng tập lệnh
Mặc dù ít trực quan hơn, nhưng bất kỳ tệp nào có định dạng tệp có thể chứa dòng đầu tiên bắt đầu #!
bằng đường dẫn đầy đủ của tệp thực thi có thể có dòng shebang. Nếu bạn làm điều này và tệp được đánh dấu thực thi, thì bạn có thể chạy nó như một chương trình ... khiến nó được mở như một tài liệu.
Một số ứng dụng sử dụng hành vi này có chủ ý. Ví dụ, trong VMware, .vmx
các tệp định nghĩa các máy ảo. Bạn có thể "chạy" một máy ảo như thể nó là một tập lệnh vì các tệp này được đánh dấu có thể thực thi được và có một dòng shebang khiến chúng được mở trong tiện ích VMware.
Dòng Shebang cho các tệp không chạy dưới dạng Scrips nhưng hành động như kịch bản
rm
loại bỏ các tập tin. Nó không phải là một ngôn ngữ kịch bản. Tuy nhiên, một tệp bắt đầu #!/bin/rm
và được đánh dấu thực thi có thể được chạy và khi bạn chạy nó, rm
được gọi trên đó, xóa nó.
Điều này thường được khái niệm hóa là "tập tin tự xóa." Nhưng các tập tin không thực sự chạy ở tất cả. Điều này giống như tình huống được mô tả ở trên cho .vmx
các tập tin.
Tuy nhiên, vì #!
dòng tạo điều kiện cho việc chạy một lệnh đơn giản (bao gồm các đối số dòng lệnh), bạn có thể thực hiện một số kịch bản theo cách này. Như một ví dụ đơn giản về một "tập lệnh" phức tạp hơn #!/bin/rm
, hãy xem xét:
#!/usr/bin/env tee -a
Thao tác này sẽ đưa đầu vào của người dùng một cách tương tác, lặp lại nó theo từng dòng của người dùng và nối nó vào cuối tệp "tập lệnh".
Hữu ích? Không hẳn. Khái niệm thú vị? Tổng cộng! Đúng. (Một chút nào đó.)
Khái niệm lập trình / lập trình tương tự về mặt khái niệm (chỉ để giải trí)
#include
. Cũng vậy,#
không có nghĩa là một bình luận.