Tôi có nên đặt #! (shebang) trong các tập lệnh Python, và nó nên ở dạng nào?


830

Tôi có nên đặt shebang trong tập lệnh Python của mình không? Ở dạng nào?

#!/usr/bin/env python 

hoặc là

#!/usr/local/bin/python

Đây có phải là di động như nhau? Hình thức nào được sử dụng nhiều nhất?

Lưu ý: các cơn lốc xoáy dự án sử dụng công việc. Mặt khác,dự án Django thì không.


70
Cái thứ hai không có khả năng di động và sẽ thất bại trên nhiều máy tính, nếu không nói là hầu hết.
Dietrich Epp

4
Làm thế nào để #!/usr/bin/pythonso sánh với các tùy chọn đầu tiên? Tôi thấy điều này trong khá nhiều mã ví dụ. Chỉnh sửa: Có thể đây là câu trả lời .. stackoverflow.com/a/2429517/1156245
geotheory


1
Tôi nói luôn luôn sử dụng nó, tại sao? "Zen Of Python" - Dòng 2 - "Rõ ràng là tốt hơn ngầm định". python.org/dev/peps/pep-0020
JayRizzo

2
Thành thật mà nói, không phải là "đúng", bởi vì bạn là tác giả không biết phiên bản chính xác của Python sẽ ở đâu khi tập lệnh được chạy. Nó sẽ là công việc của trình cài đặt để thêm shebang chính xác.
chepner

Câu trả lời:


1117

Dòng shebang trong bất kỳ tập lệnh nào xác định khả năng thực thi của tập lệnh giống như thực thi độc lập mà không cần nhập pythontrước vào thiết bị đầu cuối hoặc khi nhấp đúp vào tập lệnh trong trình quản lý tệp (khi được định cấu hình đúng). Không cần thiết nhưng thường được đặt ở đó để khi ai đó thấy tệp được mở trong trình chỉnh sửa, họ sẽ biết ngay họ đang xem gì. Tuy nhiên, dòng shebang nào bạn sử dụng IS quan trọng.

Cách sử dụng đúng cho các kịch bản Python 3 là:

#!/usr/bin/env python3

Điều này mặc định cho phiên bản 3. nhất. Đối với Python 2.7.latest sử dụng python2thay cho python3.

KHÔNG nên sử dụng những điều sau đây (trừ trường hợp hiếm hoi là bạn đang viết mã tương thích với cả Python 2.x và 3.x):

#!/usr/bin/env python

Lý do cho những khuyến nghị này, được đưa ra trong PEP 394 , là pythoncó thể tham khảo python2hoặc python3trên các hệ thống khác nhau. Nó hiện đang đề cập đến python2hầu hết các bản phân phối, nhưng điều đó có thể sẽ thay đổi tại một số điểm.

Ngoài ra, KHÔNG sử dụng:

#!/usr/local/bin/python

"python có thể được cài đặt tại / usr / bin / python hoặc / bin / python trong những trường hợp đó, #! ở trên sẽ thất bại."

- "#! / usr / bin / env python" so với "#! / Usr / local / bin / python"


4
@EliasVanOotegem Nếu bạn không thể chắc chắn rằng con trăn sẽ được tìm thấy /usr/binthì làm sao bạn có thể chắc chắn envsẽ được tìm thấy /usr/bin. Nếu python được cài đặt ở một nơi không chuẩn thì điều đó có nghĩa là python được thiết lập theo cách không chuẩn và kết quả là tập lệnh sẽ bị lỗi nhanh. Trái ngược với việc đưa ra các giả định về các thuộc tính của trình thông dịch python và hy vọng điều tốt nhất.
Cồn cát

65
@Dunes: envsẽ luôn được tìm thấy /usr/bin/và công việc của nó là xác định vị trí các thùng (như python) bằng cách sử dụng PATH. Bất kể python được cài đặt như thế nào, đường dẫn của nó sẽ được thêm vào biến này và envsẽ tìm thấy nó (nếu không, python không được cài đặt). Đó là công việc của env, đó là toàn bộ lý do tại sao nó tồn tại. Đó là điều cảnh báo môi trường (thiết lập các biến env, bao gồm các đường dẫn cài đặt và bao gồm các đường dẫn). Mọi người luôn hiểu rằng lệnh này chỉ có thể hoạt động nếu nó luôn được tìm thấy ở cùng một nơi. Đó chỉ là một sự cho trước
Elias Van Ootegem 17/12/14

3
@JFSebastian: Bạn nói đúng, nó không được bảo đảm hoặc được thi hành theo tiêu chuẩn POSIX. Tôi cho rằng đó là vì một trong những phiên bản sau này có chứa một số nội dung môi trường. Dù bằng cách nào: không, /usr/bin/envkhông được đảm bảo bởi bất kỳ tiêu chuẩn nào, ngoài quy tắc được áp dụng rộng rãi (phổ biến?) ...
Elias Van Ootegem

6
Nếu bạn đang sử dụng virtualenv, #! / Usr / local / bin / python, thậm chí nó tồn tại, sẽ bị sai.
nullas

6
Một vấn đề với điều này: theo PEP394, người ta chỉ nên sử dụng pythontệp thực thi khi tập lệnh tương thích với Python 2 và Python 3. Nếu không, nó nên trỏ đến lựa chọn thích hợp từ python2python3.
amiller27

67

Đó thực sự chỉ là vấn đề của hương vị. Thêm shebang có nghĩa là mọi người có thể gọi trực tiếp tập lệnh nếu họ muốn (giả sử nó được đánh dấu là có thể thực thi được); bỏ qua nó chỉ có nghĩa là pythonphải được gọi bằng tay.

Kết quả cuối cùng của việc chạy chương trình cũng không bị ảnh hưởng; nó chỉ là lựa chọn của phương tiện.


3
Đó chỉ là nó - không quan trọng bạn đứng về phía nào vì không có bên "đúng". Đó là một quyết định hoàn toàn chủ quan.
Amber

5
Không hơn bất kỳ quyết định tầm thường nào khác. vi.wikipedia.org/wiki/Parkinson's_Law_of_Triviality
Amber

2
Làm cách nào tôi có thể thực thi trực tiếp tệp python mà không cần lệnh 'python'?
Zen

5
@Zen Giả sử bạn đã bao gồm shebang (#! / Usr / bin / env python) trong tập lệnh của bạn, bạn chỉ cần làm cho tập lệnh của mình có thể thực thi được. Một cái gì đó giống như chmod a+x [your-script].pylàm cho nó thực thi và sau đó bạn chỉ có thể gọi ./[your-script.py]trong shell.
skålfyfan

9
Như câu trả lời bằng cách GlassGhost chỉ ra, có một lợi thế cụ thể để bao gồm nó bên cạnh hương vị: nó làm cho rõ ràng đối với một độc giả tương lai của tập tin mà họ đang đọc một kịch bản thực thi, chứ không phải là một tập tin đó là có nghĩa là để được nhập khẩu. Tương tự như các công cụ sửa đổi kiểm soát truy cập công cộng / riêng trong các ngôn ngữ có chúng, shebang rất hữu ích như tài liệu cũng như hiệu quả thực tế của chúng và trong một số trường hợp, khía cạnh tài liệu thực sự quan trọng nhất.
Đánh dấu Amery

32

Tôi có nên đặt shebang trong tập lệnh Python của mình không?

Đặt một shebang vào tập lệnh Python để chỉ ra:

  • mô-đun này có thể được chạy như một kịch bản
  • cho dù nó chỉ có thể chạy trên python2, python3 hay nó tương thích với Python 2/3
  • trên POSIX, cần thiết nếu bạn muốn chạy tập lệnh trực tiếp mà không cần gọi pythonthực thi một cách rõ ràng

Đây có phải là di động như nhau? Hình thức nào được sử dụng nhiều nhất?

Nếu bạn viết một shebang bằng tay thì luôn luôn sử dụng #!/usr/bin/env pythontrừ khi bạn có lý do cụ thể để không sử dụng nó. Hình thức này được hiểu ngay cả trên Windows (Python launcher).

Lưu ý: tập lệnh đã cài đặt nên sử dụng một tệp thực thi python cụ thể, ví dụ: /usr/bin/pythonhoặc /home/me/.virtualenvs/project/bin/python. Thật tệ nếu một số công cụ bị hỏng nếu bạn kích hoạt virtualenv trong trình bao của bạn. May mắn thay, shebang chính xác được tạo tự động trong hầu hết các trường hợp bởi setuptoolshoặc các công cụ gói phân phối của bạn (trên Windows, setuptoolscó thể .exetự động tạo tập lệnh bao bọc ).

Nói cách khác, nếu tập lệnh nằm trong kiểm tra nguồn thì có thể bạn sẽ thấy #!/usr/bin/env python. Nếu nó được cài đặt thì shebang là một đường dẫn đến một python cụ thể thực thi, chẳng hạn như #!/usr/local/bin/python (LƯU Ý: bạn không nên viết các đường dẫn từ danh mục sau theo cách thủ công).

Để chọn xem bạn nên sử dụng python, python2hoặc python3trong shebang, hãy xem PEP 394 - Lệnh "python" trên các hệ thống giống như Unix :

  • ... pythonchỉ nên được sử dụng trong dòng shebang cho các tập lệnh tương thích nguồn với cả Python 2 và 3.

  • để chuẩn bị cho một sự thay đổi cuối cùng trong phiên bản mặc định của Python, các tập lệnh chỉ dành cho Python 2 phải được cập nhật để tương thích nguồn với Python 3 hoặc sử dụng python2trong dòng shebang.


3
Câu trả lời đầu tiên thậm chí đề cập đến một PEP không có đủ upvote. Huh? Có PEP cho #!/usr/bin/env pythonchính nó?
binki

Vui lòng không sử dụng #!/usr/bin/env python. Xin đừng đề nghị "luôn luôn sử dụng" #!/usr/bin/env python. Đây là điều sai trái trong 99% trường hợp (lý do mà bạn đưa vào câu trả lời của mình).
Jay Sullivan

1
@JaySullivan bạn có hiểu sự khác biệt giữa kiểm tra nguồn và tập lệnh được cài đặt không? Tôi đứng sau đề nghị. Nó hoạt động tốt.
jfs

1
@jfs: Sau khi đọc lại bình luận của tôi, tôi thấy tôi hoàn toàn thất bại trong việc đưa ra quan điểm của mình. Ý tôi là hầu hết mọi người sẽ muốn sử dụng 'python2' hoặc 'python3', chứ không phải 'python'. Có hay không giải quyết thông qua đường dẫn đầy đủ hoặc env, về mặt kỹ thuật là câu hỏi của OP, bạn đã trả lời và tôi không đồng ý về điểm đó.
Jay Sullivan

@JaySullivan Tôi đồng ý. Bạn đã đọc các trích dẫn từ pep trong câu trả lời. Nó nói điều tương tự.
jfs

15

Nếu bạn có nhiều phiên bản Python và tập lệnh cần chạy trong một phiên bản cụ thể, thì cô ấy có thể đảm bảo sử dụng đúng phiên bản khi tập lệnh được thực thi trực tiếp, ví dụ:

#!/usr/bin/python2.7

Lưu ý rằng tập lệnh vẫn có thể được chạy thông qua một dòng lệnh Python hoàn chỉnh hoặc thông qua quá trình nhập, trong trường hợp đó, cô ấy sẽ bị bỏ qua. Nhưng đối với các kịch bản chạy trực tiếp, đây là một lý do hợp lý để sử dụng she-bang.

#!/usr/bin/env python nói chung là cách tiếp cận tốt hơn, nhưng điều này giúp với các trường hợp đặc biệt.

Thông thường sẽ tốt hơn khi thiết lập một môi trường ảo Python, trong trường hợp đó, chung #!/usr/bin/env pythonsẽ xác định đúng thể hiện của Python cho virtualenv.


Không phải là không gian sẽ làm cho nó thất bại?
RandomInsano

1
@RandomInsano, tôi không nghĩ vậy. Không gian có vẻ khá phổ biến và có rất nhiều bằng chứng xung quanh 'mạng này là một cách sử dụng được chấp nhận. Tuy nhiên tôi nghĩ không có không gian có lẽ là cách sử dụng kinh điển hơn.
Chris Johnson

1
Bạn chắc chắn đúng về điều này. Chỉ cần thử nghiệm trên bash và tcsh.
RandomInsano

Kết quả whichsẽ cung cấp cho bạn một chuỗi sẽ hoạt động, thời gian. Bạn không cần phải lo lắng về bất kỳ can đảm nào để sử dụng nó.
SDsolar

10

Bạn nên thêm một shebang nếu tập lệnh được dự định thực thi. Bạn cũng nên cài đặt tập lệnh với phần mềm cài đặt sửa đổi shebang thành một cái gì đó chính xác để nó sẽ hoạt động trên nền tảng đích. Ví dụ về điều này là distutils và Phân phối.


1
Bạn không phải sửa đổi #! dòng sau đó. Đó là những gì / usr / bin / env dành cho. Mã hóa cứng đối với trình thông dịch Python cụ thể có thể gây hại nhiều hơn là tốt. Nó rất mong manh khi cài đặt một phiên bản Python khác hoặc chuyển đổi giữa Python của chúng tôi so với cài đặt Python tùy chỉnh.
vog

Trong Ubuntu, sử dụng kết quả whichsẽ tự động chọn mặc định đang được sử dụng bởi các lệnh hệ thống và như vậy. Nó là chung chung và hệ thống chỉ đạo nó để cài đặt thích hợp.
SDsolar

9

Mục đích của shebang là để tập lệnh nhận ra loại trình thông dịch khi bạn muốn thực thi tập lệnh từ trình bao. Hầu hết, và không phải lúc nào cũng vậy, bạn thực thi các tập lệnh bằng cách cung cấp trình thông dịch ra bên ngoài. Ví dụ sử dụng:python-x.x script.py

Điều này sẽ hoạt động ngay cả khi bạn không có người khai báo shebang.

Tại sao cái đầu tiên lại "di động" hơn là bởi vì, /usr/bin/envcó chứa phần PATHkhai báo của bạn chiếm tất cả các điểm đến nơi hệ thống thực thi của bạn cư trú.

LƯU Ý: Tornado không sử dụng shebang một cách nghiêm ngặt và Django hoàn toàn không sử dụng. Nó thay đổi theo cách bạn đang thực thi chức năng chính của ứng dụng.

CSONG: Nó không thay đổi với Python.


8

Đôi khi, nếu câu trả lời là không phải là rất rõ ràng (tôi có nghĩa là bạn không thể quyết định nếu có hoặc không), sau đó nó không quan trọng quá nhiều, và bạn có thể bỏ qua các vấn đề cho đến khi câu trả lời rõ ràng.

Các #!mục đích duy nhất là để tung ra các kịch bản. Django tự tải các nguồn và sử dụng chúng. Nó không bao giờ cần phải quyết định những gì thông dịch viên nên được sử dụng. Bằng cách này, #!thực sự không có ý nghĩa ở đây.

Nói chung, nếu nó là một mô-đun và không thể được sử dụng như một tập lệnh, thì không cần sử dụng #!. Mặt khác, một nguồn mô-đun thường chứa if __name__ == '__main__': ...ít nhất một số thử nghiệm tầm thường về chức năng. Sau đó, #!có ý nghĩa một lần nữa.

Một lý do tốt để sử dụng #!là khi bạn sử dụng cả hai tập lệnh Python 2 và Python 3 - chúng phải được giải thích bởi các phiên bản Python khác nhau. Bằng cách này, bạn phải nhớ những gì pythonphải được sử dụng khi khởi chạy tập lệnh theo cách thủ công (không có #!bên trong). Nếu bạn có một hỗn hợp các tập lệnh như vậy, thì nên sử dụng phần #!bên trong, làm cho chúng có thể thực thi được và khởi chạy chúng dưới dạng thực thi (chmod ...).

Khi sử dụng MS-Windows, #!không có ý nghĩa - cho đến gần đây. Python 3.3 giới thiệu Windows Python Launcher (py.exe và pyw.exe) đọc #!dòng, phát hiện các phiên bản Python đã cài đặt và sử dụng phiên bản Python chính xác hoặc mong muốn rõ ràng. Vì tiện ích mở rộng có thể được liên kết với một chương trình, bạn có thể có hành vi tương tự trong Windows như với cờ thực thi trong các hệ thống dựa trên Unix.


3

Khi tôi cài đặt Python 3.6.1 trên Windows 7 gần đây, nó cũng đã cài đặt Python Launcher cho Windows, được cho là để xử lý dòng shebang. Tuy nhiên, tôi thấy rằng Trình khởi chạy Python không làm điều này: dòng shebang bị bỏ qua và Python 2.7.13 luôn được sử dụng (trừ khi tôi thực thi tập lệnh bằng py -3).

Để khắc phục điều này, tôi đã phải chỉnh sửa khoá đăng ký Windows HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.File\shell\open\command. Điều này vẫn có giá trị

"C:\Python27\python.exe" "%1" %*

từ bản cài đặt Python 2.7 trước đó của tôi. Tôi đã sửa đổi giá trị khóa đăng ký này thành

"C:\Windows\py.exe" "%1" %*

và xử lý dòng shebang Python Launcher hoạt động như mô tả ở trên.


2

Nếu bạn đã cài đặt các mô-đun khác nhau và cần sử dụng một cài đặt python cụ thể, thì shebang ban đầu dường như bị hạn chế. Tuy nhiên, bạn có thể thực hiện các thủ thuật như dưới đây để cho phép shebang được gọi trước tiên dưới dạng tập lệnh shell và sau đó chọn python. Điều này rất linh hoạt imo:

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $PREFERRED_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

Hoặc tốt hơn, có lẽ, để tạo điều kiện tái sử dụng mã trên nhiều tập lệnh python:

#!/bin/bash
"true" '''\'; source $(cd $(dirname ${BASH_SOURCE[@]}) &>/dev/null && pwd)/select.sh; exec $CHOSEN_PYTHON "$0" "$@"; exit 127; '''

và sau đó select.sh có:

PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    CHOSEN_PYTHON=$PREFERRED_PYTHON
elif [ -x $ALTERNATIVE_PYTHON ]; then
    CHOSEN_PYTHON=$ALTERNATIVE_PYTHON
else
    CHOSEN_PYTHON=$FALLBACK_PYTHON
fi

1
Mặc dù tôi không chắc chắn rằng một polyglot như thế này nói chung là cách thực hành tốt, nhưng đó chắc chắn là cách tiếp cận rất thú vị và có lẽ là câu trả lời linh hoạt nhất ở đây.
Ryan Amos

1
Rất tuyệt. Tôi không nhận ra bạn có thể làm điều đó
user2233949

1

Trả lời: Chỉ khi bạn có kế hoạch biến nó thành tập lệnh thực thi dòng lệnh.

Đây là thủ tục:

Bắt đầu bằng cách xác minh chuỗi shebang thích hợp để sử dụng:

which python

Lấy đầu ra từ đó và thêm nó (với shebang #!) Trong dòng đầu tiên.

Trên hệ thống của tôi, nó phản hồi như vậy:

$which python
/usr/bin/python

Vì vậy, shebang của bạn sẽ trông như:

#!/usr/bin/python

Sau khi lưu, nó vẫn sẽ chạy như trước vì python sẽ thấy dòng đầu tiên đó là một nhận xét.

python filename.py

Để làm cho nó một lệnh, sao chép nó để thả phần mở rộng .py.

cp filename.py filename

Nói với hệ thống tập tin rằng điều này sẽ được thực thi:

chmod +x filename

Để kiểm tra nó, sử dụng:

./filename

Cách thực hành tốt nhất là di chuyển nó đến một nơi nào đó trong $ PATH của bạn để tất cả những gì bạn cần nhập là tên tệp.

sudo cp filename /usr/sbin

Bằng cách đó, nó sẽ hoạt động ở mọi nơi (không có ./ trước tên tệp)


Tôi nghi ngờ rằng đây là cách thực hành tốt nhất và tôi thực sự khuyên bạn nên sử dụng giải pháp của GlassGhost .
colidyre

Tôi thấy điều này hữu ích và nó làm việc rất tốt cho tôi. điều này đã được giải thích tốt. Tuy nhiên, tôi sẽ đánh giá cao ý kiến ​​cho thấy tại sao đây không phải là một thực tiễn tốt nhất. Tôi rất ham học hỏi.
Charles Carriere

0

Đường dẫn tuyệt đối và hợp lý:

Đây thực sự là một câu hỏi về việc đường dẫn đến trình thông dịch Python nên tuyệt đối hay hợp lý ( /usr/bin/env) đối với tính di động.

Gặp phải câu trả lời khác trên trang này và các trang Stack khác nói về vấn đề này một cách tổng quát mà không cần bằng chứng hỗ trợ, tôi đã thực hiện một số thực sự, THỰC SỰ , kiểm tra và phân tích chi tiết về chính câu hỏi này trên unix.stackexchange.com . Thay vì dán câu trả lời ở đây, tôi sẽ chỉ những người quan tâm đến phân tích so sánh với câu trả lời đó:

https://unix.stackexchange.com/a/566019/334294

Là một Kỹ sư Linux, mục tiêu của tôi là luôn cung cấp các máy chủ được tối ưu hóa, phù hợp nhất cho các máy khách phát triển của mình, vì vậy vấn đề về môi trường Python là điều tôi thực sự cần một câu trả lời chắc chắn. Quan điểm của tôi sau khi thử nghiệm là con đường logic trong cô ấy là tốt hơn trong các tùy chọn (2).


-3

Sử dụng trước

which python

Điều này sẽ cung cấp đầu ra là vị trí có trình thông dịch python (nhị phân) của tôi.

Đầu ra này có thể là bất kỳ như

/usr/bin/python

hoặc là

/bin/python

Bây giờ chọn một cách thích hợp các dòng shebang và sử dụng nó.

Để khái quát chúng ta có thể sử dụng:

#!/usr/bin/env

hoặc là

#!/bin/env

3
Điều này có lẽ sẽ không thể di chuyển đến các hệ thống khác. #!/usr/bin/envđưa ra lựa chọn đúng đắn cho bạn
phân mảnh thực tế

Đó là lý do tại sao bạn sử dụng whichlệnh - nó sẽ trả về chuỗi chính xác cho hệ thống cụ thể của bạn.
SDsolar

1
... và sau đó mỗi khi tập lệnh được thực thi trên một máy khác, bạn chạy which pythonlại và thay đổi tập lệnh nếu đầu ra khác với shebang hiện tại
phân mảnh thực tế

2
-1 Đây là giải pháp dễ vỡ nhất có thể. Nó chỉ được đảm bảo là chính xác cho hệ thống mà tập lệnh python của bạn được viết. Sử dụng #! / Usr / bin / env python3 cho tính di động
Myles Hollowed
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.