Câu hỏi khá đơn giản: Trong Linux, tại sao Python yêu cầu dòng
#!/usr/bin/python
khi bắt đầu tập tin python, vì Windows không?
Nó làm gì? 'Vì mô tả "Liên kết đến Python" hơi mơ hồ ...
python myscript.py
thay thế.
Câu hỏi khá đơn giản: Trong Linux, tại sao Python yêu cầu dòng
#!/usr/bin/python
khi bắt đầu tập tin python, vì Windows không?
Nó làm gì? 'Vì mô tả "Liên kết đến Python" hơi mơ hồ ...
python myscript.py
thay thế.
Câu trả lời:
Python không có bất kỳ yêu cầu đặc biệt nào như vậy trên Linux. Đó là trình tải chương trình trên Unix / Linux sử dụng dòng "shebang", như cách gọi của nó. Đây thực sự là một tính năng chứ không phải là một giới hạn, nhưng chúng ta sẽ đến đó ngay lập tức. Trang Wiki trên "shebang" có nhiều chi tiết hơn, nhưng tôi sẽ cố gắng đưa ra một cái nhìn tổng quan cũng như so sánh với Windows tại đây.
Trước tiên, hãy xem xét tình hình trên Windows:
.
Trong trường hợp tệp Python, đây thường là .py
..py
các tệp nên được mở bằng ứng dụng Python mới được cài đặt (tức là trình thông dịch Python)..exe
và .bat
các tệp được thực thi dưới dạng các tập lệnh bó của Windows..py
các tệp bằng cách sử dụng python.exe
, nó sẽ mở chúng bằng một số chương trình khác, chẳng hạn như trình soạn thảo văn bản notepad.exe
.
python <scriptname>.py
(hoặc viết .bat
tệp để thực hiện việc này cho bạn).Bây giờ, điều gì xảy ra nếu có một dòng shebang ( #!/usr/bin/python
hoặc #!/usr/bin/env python
) ở đầu tập lệnh Python? Chà, vì #
là một dòng bình luận trong Python, trình thông dịch Python chỉ bỏ qua nó. Đây là một lý do tại sao hầu hết các ngôn ngữ script được sử dụng trong thế giới Unix / Linux sử dụng #
để bắt đầu các dòng bình luận.
Vì vậy, có một chút sai lầm khi nói rằng Windows "không cần" #!
dòng; Windows không nhìn thấy những #!
dòng, và trong thực tế dựa trên các tập tin có phần mở rộng để cho nó phải làm gì. Điều này có một vài nhược điểm:
.py
ở cuối để chúng tự động được nhận dạng như vậy..py
tệp, Windows sẽ không còn tự động chạy các tập lệnh đó bằng Python. Lưu ý rằng điều này có thể được thực hiện ngoài ý muốn.Bây giờ, hãy xem cách Unix / Linux khởi chạy các tập lệnh:
Điều đầu tiên cần lưu ý là Unix / Linux, không giống như Windows, không cố gắng "mở" các tập lệnh Python bằng một chương trình cụ thể, ít nhất là về mặt khái niệm; HĐH biết rằng tập lệnh là thứ có thể được thực thi do một thứ gọi là "bit thực thi" (nằm ngoài phạm vi của câu trả lời này). Vì vậy, nếu bạn vô tình gõ #!/usr/bin/pthon
thay vì #!/usr/bin/python
, bạn sẽ nhận được thông báo lỗi bao gồm văn bản này:
/usr/bin/pthon: bad interpreter: No such file or directory.
Từ "thông dịch viên" cho chúng ta manh mối về vai trò của dòng shebang (mặc dù về mặt kỹ thuật, chương trình được chỉ định có thể là một cái gì đó khác với trình thông dịch, chẳng hạn như cat
hoặc trình soạn thảo văn bản). Khi bạn cố gắng thực thi một tập tin, đây là những gì xảy ra:
#!
, thì trình tải sẽ diễn giải phần còn lại của dòng shebang (không bao gồm chính shebang) như một lệnh để khởi chạy trình thông dịch để chạy nội dung tệp dưới dạng tập lệnh.Điều này có một vài lợi thế:
Lưu ý, cuối cùng, Unix / Linux không cần dòng shebang để chạy tập lệnh Python. Hãy nhớ lại rằng tất cả các dòng shebang thực sự làm là cho phép trình tải chương trình chọn một trình thông dịch. Nhưng cũng giống như trong Windows, điều này có thể được thực hiện thủ công:
python <myscript>
.py2
và các .py3
phần mở rộng cho các tập lệnh Python 2 / Python 3. Vì vậy, cả Linux (+ x bit) và Windows (phần mở rộng tệp) đều cần siêu dữ liệu trong hệ thống tệp. Sự khác biệt chính là bit + x dễ bị mất hơn trong quá trình vận chuyển. Đây không hẳn là nhược điểm.
/usr/bin/i686/python
và /usr/bin/amd64/python
thì sao? Hoàn toàn hợp lý, nhưng nó phá vỡ các kịch bản python có giả định được mã hóa cứng /usr/bin/python
. Sự lựa chọn của trình thông dịch không phải là sự lựa chọn của người viết kịch bản mà là của người sử dụng tập lệnh, Người viết kịch bản chỉ được chọn ngôn ngữ (phương ngữ).
/usr/bin/env
, cùng với các tập lệnh env-setup. Phiên bản Windows này là gì? Chạy một regedit
kịch bản ngay trước khi bạn khởi chạy một .py
tệp để đảm bảo rằng bạn có được trình thông dịch bạn muốn?
Dòng bạn đã chỉ định được sử dụng để báo cho máy tính biết chương trình / trình thông dịch nào sẽ sử dụng khi chạy tệp / tập lệnh trực tiếp và bất kỳ đối số nào sẽ được chuyển đến chương trình đó khi tập lệnh chạy. Tuy nhiên, đây không phải là yêu cầu của Python , đây là yêu cầu của kernel / system linux nếu bạn có ý định chạy script trực tiếp (và không chuyển nó cho Python theo cú pháp dưới đây).
Nó không cần thiết nếu bạn sẽ thực hiện python script.py
hoặc tương tự. Nó chỉ cần thiết nếu bạn có ý định chạy tập lệnh / tập tin trực tiếp mà không cung cấp trình thông dịch để sử dụng (chẳng hạn như python
).
Đối với một kịch bản Bash, nó sẽ có một cái gì đó như thế này:
#!/bin/bash [optional Bash arguments]
# Bash script code here
...
exit 0;
Điều này sẽ chỉ ra cho hệ thống rằng, khi nó chạy, nó sẽ được chạy qua /bin/bash
đó là một trong những ngôn ngữ shell / shell-script trên hệ thống.
Mặc dù vậy, đối với mã Python, ở đây, bạn sẽ muốn có tệp thực thi chạy qua Python, vì vậy bạn cho nó biết trình thông dịch nào bạn định chạy trong đó.
#!/usr/bin/python [optional Python arguments]
# Python code here
...
exit()
Điều này, giống như đối với Bash, chỉ ra rằng /usr/bin/python
nên được sử dụng (đây có thể là Python 2 hoặc Python 3, tùy thuộc vào cấu hình hệ thống riêng của bạn).
Bằng cách này, bạn có thể chạy ./filename.py
hoặc ./executable
hoặc ./scripttorun
trực tiếp.
Nếu không có dòng đó ngay từ đầu và giả sử bạn đã đặt tệp / tập lệnh thành có thể thực thi được và giả sử bạn đang làm việc với tập lệnh Python, bạn sẽ phải chạy python filename.py
hoặc tương tự nếu bạn không có #!/usr/bin/python
dòng đó. (Đối với tập lệnh Bash, bạn sẽ phải thực hiện bash script.sh
hoặc tương tự đối với các tập lệnh / ngôn ngữ khác, chẳng hạn như Perl, Ruby, v.v.)
Cú pháp tô sáng ở trên là ngôn ngữ cụ thể trong từng phần, mặc dù nó không thực sự quan trọng.
#!/bin/bash -x
, #!/usr/bin/perl -lan
, vv).
/usr/bin/env python
để có được con trăn chính xác.
env
là gì, nhưng vấn đề dường như không phải là số lượng đối số: #!/usr/bin/perl -l -a -n
có ba đối số nhưng nó hoạt động. Mặc dù một lần nữa, tôi không thể tìm ra vấn đề chính xác.
./
. Nói cách khác chỉ python filename.py
hoặc bash script.sh
sẽ làm việc tốt. Lý do duy nhất để bao gồm ./
là trong một tên lệnh, khi bạn muốn nói với shell không tìm kiếm trong $PATH
đó (có thể không tìm thấy các tệp trong thư mục hiện tại) nhưng đi theo đường dẫn mà bạn đã chỉ định. Nhưng điều đó không áp dụng cho các đối số lệnh.
env
nhận phần còn lại của các đối số từ kernel. Tất cả chúng có thể được coi là một đối số lớn mà không có sự phân tách theo không gian được thực hiện. Xin lỗi vì khớp nối, tôi không còn nhớ chi tiết về điều này nữa
Dòng:
#!/usr/bin/python
được gọi là 'shebang' và nó chỉ ra đường dẫn đến nhị phân trình thông dịch sẽ được sử dụng để giải thích phần còn lại của các lệnh trong tệp. Nó thường là dòng đầu tiên của một kịch bản.
Vì vậy, dòng #!/usr/bin/python
chỉ ra rằng nội dung của tệp sẽ được giải thích bởi python
nhị phân nằm ở /usr/bin/python
.
Lưu ý rằng dòng shebang được phân tích cú pháp bởi kernel và sau đó tập lệnh cuối cùng sẽ được gọi là đối số:
python script_name
Tương tự trong trường hợp #!/bin/bash
:
bash script_name
shebang
. Vì từ này được hình thành từ "băm" và "bang", nên cách đánh vần của bạn không rõ ràng lắm, vì có vẻ như đó là sự kết hợp của "cô ấy" và "bang".
hashbang
( #
= "băm") hoặc shebang
( #
= "sharp"), tùy thuộc vào cách bạn đặt tên cho #
ký tự. Tuy nhiên, shebang
thực sự là phổ biến hơn. @KyleStrand
Về mặt kỹ thuật, nó không yêu cầu nó. Nó đòi hỏi một đường dẫn đến môi trường nơi tập lệnh của bạn thực thi. Các tập lệnh trong tương lai của bạn sẽ tốt hơn để bao gồm / usr / bin / env sau đó, chỉ định python. Cấp quyền này mà tập lệnh của bạn chạy trong môi trường python cho dù python được cài đặt ở đâu. Bạn muốn làm điều này vì lý do tương thích, bạn không thể chắc chắn rằng người tiếp theo bạn chia sẻ mã của mình sẽ có python được cài đặt trong usr / bin / python hoặc họ sẽ có quyền đối với các tệp hệ thống đó.
Đây là một câu hỏi và trả lời tương tự từ tràn ngăn xếp .
Những gì trông giống như trong kịch bản của bạn là:
#!/usr/bin/env python
Tôi cũng thấy một số lo ngại về cách chỉ định python3. Đây là cách làm:
#!/usr/bin/env python3
Trong Linux, Python có thể hoặc không yêu cầu dòng #!
(shebang). Điều này phụ thuộc vào cách xử lý mã Python, chạy mã trong chế độ tương tác Python hoặc trong tập lệnh Python.
Chế độ tương tác Python cho phép người dùng nhập và chạy mã Python trực tiếp, không yêu cầu dòng shebang. Để chạy chế độ tương tác, hãy mở Terminal và gõ python
cho Python 2.X hoặc python3
cho Python 3.X.
$ python
Python 2.7.6 (default, Jun 22 2015, 18:00:18)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
$ python3
Python 3.4.3 (default, Oct 14 2015, 20:33:09)
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Tập lệnh Python cho phép người dùng viết và lưu mã Python trong tệp văn bản thuần túy, sau đó chạy mã sau. Điều này có thể hoặc không yêu cầu dòng shebang. Tuy nhiên, có hai lý do được biết khi dòng shebang được yêu cầu để sử dụng tập lệnh Python trong Linux.
để chạy mã Python trong một tập lệnh thực thi, nghĩa là xác định cách chạy mã và sử dụng trình thông dịch gì;
để chạy mã Python liên quan đến phiên bản cụ thể của Python, tức là chạy mã tương thích với Python 2.X hoặc Python 3.X
Thực hành với các kịch bản Python
Dưới đây là danh sách và nội dung của các tệp mà tôi đã sử dụng để hiển thị các trường hợp #!
dòng (shebang) là bắt buộc hoặc không bắt buộc.
$ ls -ln *.py
-rw-rw-r-- 1 1000 1000 94 Dec 14 18:37 hello1.py
-rwxrwxr-x 1 1000 1000 116 Dec 14 18:37 hello2e.py
-rw-rw-r-- 1 1000 1000 116 Dec 14 18:37 hello2.py
-rwxrwxr-x 1 1000 1000 117 Dec 14 18:37 hello3e.py
-rwxrwxr-x 1 1000 1000 120 Dec 14 18:37 hello3m.py
-rw-rw-r-- 1 1000 1000 117 Dec 14 18:37 hello3.py
$ file *.py
hello1.py: ASCII text
hello2e.py: Python script, ASCII text executable
hello2.py: Python script, ASCII text executable
hello3e.py: Python script, ASCII text executable
hello3m.py: Python script, UTF-8 Unicode (with BOM) text executable
hello3.py: Python script, ASCII text executable
hello1.py
chỉ chứa mã nguồn.
import sys
sys.stdout.write("Hello from Python %s\n" % (sys.version,))
print("Hello, World!")
hello2.py
chứa mã nguồn và dòng shebang.
#!/usr/bin/env python
import sys
sys.stdout.write("Hello from Python %s\n" % (sys.version,))
print("Hello, World!")
hello2e.py
chứa giống như hello2.py
và thực hiện.
hello3.py
chứa tương tự hello2.py
, ngoại trừ nó được điều chỉnh để chạy với Python 3 bằng cách đổi tên dòng đầu tiên thành #!/usr/bin/env python3
.
hello3e.py
chứa giống như hello3.py
và thực hiện.
hello3m.py
chứa giống như hello3.py
và được thực thi, ngoại trừ được lưu với Write Unicode BOM
tùy chọn trong trình soạn thảo văn bản, ví dụ như Mousepad.
Ngoài thời điểm này, người dùng sẽ được trình bày hai phương thức để chạy các tập lệnh Python. Cả hai phương pháp đã được chứng minh như dưới đây.
Phương pháp 1: Chạy với chương trình Python
Dưới đây là các lệnh và đầu ra khi chạy mã nguồn với Python 2 và Python 3.
$ python hello1.py
Hello from Python 2.7.6 (default, Jun 22 2015, 18:00:18)
[GCC 4.8.2]
Hello, World!
$ python3 hello1.py
Hello from Python 3.4.3 (default, Oct 14 2015, 20:33:09)
[GCC 4.8.4]
Hello, World!
Cả hai phiên bản Python đều có thể chạy tập lệnh thành công. Do đó, dòng shebang không bắt buộc khi chạy tập lệnh Python thông qua python
hoặc python3
lệnh.
Phương pháp 2: Chạy dưới dạng tập lệnh Python
Dưới đây là các lệnh và đầu ra khi chạy mã nguồn với dòng shebang, được điều chỉnh cho cả Python 2 và Python 3, bao gồm cả các trường hợp không thể thực thi và thực thi.
$ ./hello1.py
bash: ./hello1.py: Permission denied
$ ./hello2.py
bash: ./hello2.py: Permission denied
$ ./hello3.py
bash: ./hello3.py: Permission denied
$ ./hello2e.py
Hello from Python 2.7.6 (default, Jun 22 2015, 18:00:18)
[GCC 4.8.2]
Hello, World!
$ ./hello3e.py
Hello from Python 3.4.3 (default, Oct 14 2015, 20:33:09)
[GCC 4.8.4]
Hello, World!
Ba tập lệnh đầu tiên đã thất bại vì các tập lệnh này không thể thực thi được, bất kể có dòng shebang hay không (Để biết bằng chứng hỗ trợ, xem ví dụ bổ sung bên dưới). Hai tập lệnh cuối cùng có dòng shebang và có thể thực thi được.
Rõ ràng, một kịch bản đã được thực thi thực chất là vô dụng nếu không có dòng shebang. Do đó, dòng shebang là bắt buộc và tập lệnh phải được thực thi khi chạy mã Python trong tập lệnh thực thi.
Khi shebang không hoạt động
Trong ví dụ đã được chuẩn bị và thử nghiệm của tôi, việc chạy hello3m.py
như một tập lệnh thực thi đã thất bại và trả về lỗi.
$ ./hello3m.py
./hello3m.py: line 1: #!/usr/bin/env: No such file or directory
Đây là một hạn chế đã biết rằng shebang không hoạt động hoặc trở nên không hợp lệ. Khi một tệp được lưu dưới dạng Unicode BOM (Dấu thứ tự Byte), nó sẽ không chạy bình thường như một tập lệnh Python thực thi.
Ví dụ bổ sung
Ví dụ bổ sung này chỉ được coi là bằng chứng hỗ trợ. Người dùng nên tránh chạy ví dụ này, mặc dù kết quả là vô hại.
Tôi đã tạo một tập tin khác có tên hello1e.py
, chứa hello1.py
và thực hiện. Chạy tập lệnh này trả về một lỗi cú pháp.
$ ./hello1e.py
./hello1e.py: line 2: syntax error near unexpected token `"Hello from Python %s\n"'
./hello1e.py: line 2: `sys.stdout.write("Hello from Python %s\n" % (sys.version,))'
Khi chạy tập lệnh này, lúc đầu, con trỏ chuột sẽ được thay đổi thành dấu cộng và không có gì xuất hiện. Lỗi cú pháp sẽ không được hiển thị cho đến khi tôi nhấp vào cửa sổ Desktop hoặc Terminal. Sau đó, tập lệnh này sẽ tạo một sys
tệp trong cùng thư mục với tập lệnh.
$ file sys
sys: PostScript document text conforming DSC level 3.0, Level 1
Các sys
tập tin đã được xác định là tập tin PostScript, mà không cần phần mở rộng tập tin. Tệp này có thể được mở trong trình xem tài liệu, ví dụ Evince và tệp thực sự chứa ảnh chụp màn hình của cửa sổ mà tôi đã nhấp trước đó. Theo kinh nghiệm của tôi, tệp có thể lớn tới vài Megabyte.
Một lần nữa, dòng shebang là bắt buộc và tập lệnh phải được thực thi khi chạy tập lệnh Python dưới dạng tập lệnh thực thi. Nếu không, kịch bản sẽ hoạt động sai như mô tả ở trên.
Ghi chú bổ sung
Thuật ngữ "được thực thi" hoặc "phải được thực thi" dùng để chỉ sự cho phép chạy tập lệnh. Điều này được thực hiện bằng cách chạy chmod +x FILENAME
lệnh trong Terminal hoặc bằng cách chọn tùy chọn "Cho phép tệp này chạy dưới dạng chương trình" hoặc một cái gì đó tương tự trong cửa sổ Thuộc tính , trong trình quản lý tệp.
Trong khi các câu trả lời hiện có khác đã bao gồm hầu hết mọi thứ, câu trả lời này đã có cách tiếp cận khác bằng cách sử dụng các ví dụ thực tế để giải thích vấn đề. Cú pháp mã đã được viết cẩn thận, sao cho các ví dụ có thể được chạy với Python 2 hoặc Python 3, như vậy.
Các mã Python đã được điều chỉnh từ Sử dụng Python trên Windows và Sử dụng Python trên các nền tảng Unix , với mã một dòng bổ sung phổ biến "Xin chào, Thế giới!" chương trình.
Tất cả các mã và lệnh đã được kiểm tra đầy đủ và hoạt động trong hệ thống Xubfox 14.04, có cài đặt Python 2.7 và Python 3.4 theo mặc định.
Điều đó có nghĩa là khi tệp đó được thực thi, máy tính của bạn sẽ biết thực thi nó với chương trình /usr/bin/python
, đó là cách bạn phân biệt nó với ngôn ngữ khác, chẳng hạn như bash nơi bạn sẽ làm #!/bin/bash
. Điều này là để bạn có thể chạy một cách đơn giản:
./[file-to-execute]
Và nó sẽ biết tập tin nào để thực thi nó, thay vì chính bạn phải chỉ định với một cái gì đó như:
python ./[file-to-execute].py
Phần #!
thường được coi là một shebang hoặc crunch bang .
Nếu bạn đã cài đặt một số phiên bản Python, /usr/bin/env
sẽ đảm bảo trình thông dịch được sử dụng là phiên bản đầu tiên trên môi trường của bạn $PATH
. Thay thế sẽ là mã hóa một cái gì đó như #!/usr/bin/python
;
Trong Unix, một tệp thực thi có nghĩa là được giải thích có thể chỉ ra trình thông dịch nào sẽ sử dụng bằng cách #!
bắt đầu dòng đầu tiên, theo sau là trình thông dịch (và bất kỳ cờ nào có thể cần).
Quy tắc này chỉ áp dụng cho hệ thống dựa trên UNIX.
hữu ích cho các hệ điều hành như Linux, nơi Python 2.x vẫn là tiêu chuẩn, nhưng hầu hết mọi người cũng tải xuống 3.x.
2.x sẽ chạy theo mặc định. Vì vậy, mã 3.x của tôi, tôi có tiền tố với #! / Usr / bin / env python3 để 3.x chạy mã. Tôi thậm chí có thể chỉ định xuống bản sửa đổi nhỏ (python 3.xyz) nếu tôi chọn bản beta hoặc phiên bản cũ hơn một chút.
.
) để xác định loại tệp đó là gì. Ngay cả Windows cũng đang tránh xa điều này: kiểm tra một vài dòng đầu tiên của tệp Microsoft Word và nó sẽ cho biết trên thực tế, đó là một tệp Microsoft Word.