variable - python windows path




為什麼人們在Python腳本的第一行寫入#!/ usr/bin/env python shebang? (14)

在我看來,這些文件在沒有該行的情況下運行相同。

如果是這樣,那麼也許你在Windows上運行Python程序? Windows不使用該行 - 相反,它使用文件擴展名來運行與文件擴展名關聯的程序。

然而在2011年,開發了一個“Python啟動器” ,它在某種程度上模仿了Windows的這種Linux行為。 這僅限於選擇運行哪個Python解釋器 - 例如,在安裝了兩者的系統上選擇Python 2和Python 3。 啟動程序可以通過Python安裝選擇性安裝為py.exe ,並且可以與.py文件關聯,以便啟動程序將檢查該行並反過來啟動指定的Python解釋器版本。

在我看來,這些文件在沒有該行的情況下運行相同。


Linux內核的exec系統調用本地理解shebang( #!

當你在bash上做:

./something

在Linux上,這將調用具有完整路徑的exec系統調用。

內核的這一行被傳遞給exec的文件調用: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

如果((bprm-> buf [0]!='#')||(bprm-> buf [1]!='!'))

這讀取文件的第一個字節,並將它們與#!進行比較 。

如果是這樣的話,那麼其餘的行被Linux內核解析,這使得另一個調用路徑/usr/bin/env python和當前文件作為第一個參數的exec調用:

/usr/bin/env python /path/to/script.py

這適用於使用#作為註釋字符的任何腳本語言。

是的,你可以通過以下途徑進行無限循環:

#!/a

和一個在/a的可執行文件

#! 只是碰巧是人類可讀的,但這不是必需的。

如果文件以不同的字節開始,那麼exec系統調用將使用不同的處理程序。 另一個最重要的內置處理程序是用於ELF可執行文件的: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305它檢查字節7f 45 4c 46 (它也是碰巧是人類可讀的.ELF )。 這將讀取ELF文件,將其正確放入內存中,並使用它啟動新的進程。 另請參閱: 內核如何獲得在Linux下運行的可執行二進製文件?

最後,您可以使用binfmt_misc機制添加您自己的shebang處理程序。 例如,您可以為.jar文件添加自定義處理程序: 運行JAR文件而不直接調用`java`此機制甚至通過文件擴展名支持處理程序。

但是,我不認為POSIX指定了shebangs: https://unix.stackexchange.com/a/346214/32558 ://unix.stackexchange.com/a/346214/32558,儘管它提到了基本原理部分,並且採用了“如果系統支持可執行腳本,發生”。


你可以使用virtualenv來嘗試這個問題

這裡是test.py

#! /usr/bin/env python
import sys
print(sys.version)

創建虛擬環境

virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7

激活每個環境然後檢查差異

echo $PATH
./test.py

在其他答案上稍微擴展一下,下面是一個小例子,說明你的命令行腳本如何不小心使用/usr/bin/env shebang行:

$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py 
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py 
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py 
Traceback (most recent call last):
  File "./my_script.py", line 2, in <module>
    import json
ImportError: No module named json

Python 2.5中不存在json模塊。

防止出現這種問題的一種方法是使用通常與大多數Pythons一起安裝的版本化Python命令名稱:

$ cat my_script.py 
#!/usr/bin/env python2.6
import json
print "hello, json"

如果您只需要區分Python 2.x和Python 3.x,則最新版本的Python 3也提供了python3名稱:

$ cat my_script.py 
#!/usr/bin/env python3
import json
print("hello, json")

如果您安裝了多個版本的Python,則/usr/bin/env將確保使用的解釋器是環境$PATH的第一個。 另一種方法是硬編碼像#!/usr/bin/python ; 沒關係,但不夠靈活。

在Unix中,一個可解釋的可執行文件可以通過#!來指示要使用的解釋器#! 在第一行的開始,然後是解釋器(以及它可能需要的任何標誌)。

如果你在談論其他平台,當然這個規則不適用(但是“shebang line”不會造成任何損害,並且如果你將這個腳本複製到一個具有 Unix基礎的平台 ,比如Linux,Mac等)。


它只是指定你想要使用的解釋器。 要理解這一點,請通過執行touch test.py通過終端創建一個文件,然後在該文件中輸入以下內容:

#!/usr/bin/env python3
print "test"

並執行chmod +x test.py以使您的腳本可執行。 在此之後,當你做./test.py你應該得到一個錯誤:

  File "./test.py", line 2
    print "test"
               ^
SyntaxError: Missing parentheses in call to 'print'

因為python3不支持打印操作符。

現在繼續,將代碼的第一行更改為:

#!/usr/bin/env python2

它會工作,打印test到標準輸出,因為python2支持打印操作員。 所以,現在你已經學會瞭如何在腳本解釋器之間切換。


強調大多數錯過的一件事可能是有道理的,這可能會阻止立即理解。 在終端中鍵入python ,通常不提供完整路徑。 相反,可執行文件在PATH環境變量中查找。 反過來,當你想直接執行一個Python程序, /path/to/app.py app.py時 ,必須告訴shell使用什麼解釋器(通過hashbang ,其他貢獻者正在上面解釋什麼)。

Hashbang希望完整的解釋器。 因此,為了直接運行你的Python程序,你必須提供Python二進製文件的完整路徑,這個路徑顯著不同,尤其是考慮到使用virtualenv 。 為了解決可移植性,使用/usr/bin/env的技巧。 後者原本是為了在原地改變環境並在其中運行命令。 當沒有提供修改時,它在當前環境中運行該命令,這有效地導致相同的PATH查找,從而實現該技巧。

來自unix stackexchange


技術上來說,在Python中,這只是一條評論線。

只有從shell (從命令行)運行py腳本時才會使用此行。 這被稱為"Shebang!" ,並且它在各種情況下使用,而不僅僅用於Python腳本。

在這裡,它指示shell啟動特定版本的Python(以處理文件的其餘部分。


為了運行python腳本,我們需要告訴shell三件事情:

  1. 該文件是一個腳本
  2. 我們想要執行腳本的解釋器
  3. 說解釋者的路徑

shebang #! 完成(1.)。 shebang以#開始,因為#字符是許多腳本語言中的註釋標記。 因此shebang行的內容會被解釋器自動忽略。

env命令完成(2.)和(3.)。 引用“grawity”,

env命令的一個常見用途是啟動解釋器,通過使用env將搜索$ PATH來發送命令的事實。 由於shebang行需要指定絕對路徑,並且由於各種解釋器(perl,bash,python)的位置可能有很大差異,所以通常使用:

#!/usr/bin/env perl而不是試圖猜測它是/ bin / perl,/ usr / bin / perl,/ usr / local / bin / perl,/ usr / local / pkg / perl,/ fileserver / usr / bin / perl或/ home / MrDaniel / usr / bin / perl在用戶的系統上...

另一方面,env幾乎總是在/ usr / bin / env中。 (除非情況不是這樣,有些系統可能會使用/ bin / env,但這是非常罕見的情況,只會發生在非Linux系統上。)


考慮到python2python3之間的可移植性問題,除非你的程序與兩者兼容,否則你應該總是指定任一版本。

一些發行版現在將python符號鏈接到python3一段時間 - 不要依賴python作為python2

PEP 394強調了這一點:

為了容忍跨平台的差異,需要調用Python解釋器的所有新代碼都不應該指定python,而應該指定python2或python3(或更具體的python2.x和python3.x版本;請參閱Migration Notes ) 。 這種區別應該在shebangs中進行,當從shell腳本調用時,通過system()調用調用時,或者在任何其他上下文中調用時。


這意味著更多的歷史信息而不是“真實”的答案。

請記住,在那天你有許多unix像操作系統,其設計者都有自己的放置位置的概念,有時甚至不包括Python,Perl,Bash或許多其他GNU / Open Source的東西。

對於不同的Linux發行版甚至也是如此。 在Linux上 - pre-FHS [1] - 你可能在/ usr / bin /或/ usr / local / bin /中有python。 或者它可能沒有安裝,所以你建立了你自己的,並把它放在〜/ bin

Solaris是我工作過的最差的,部分是從Berkeley Unix到System V的過渡。你可以在/ usr /,/ usr / local /,/ usr / ucb,/ opt /等結束。對於一些非常長的路徑。 我記得從Sunfreeware.com安裝每個軟件包到它自己的目錄中的東西,但我不記得它是否將二進製文件符號鏈接到/ usr / bin中。

哦,有時/ usr / bin在NFS服務器上[2]。

所以env工具就是為了解決這個問題而開發的。

然後你可以編寫#!/bin/env interpreter ,只要路徑合適,事情就有合理的運行機會。 當然, 合理的意思是(對於Python和Perl)你也設置了合適的環境變量。 對於bash / ksh / zsh,它剛剛工作。

這很重要,因為人們在shell腳本中傳遞(如perl和python),如果你在Red Hat Linux工作站上硬編碼/ usr / bin / python,它會在SGI上壞掉......好吧,沒有,我認為IRIX把python放在了正確的位置上。 但在Sparc車站,它可能無法運行。

我想念我的斯巴達站。 但不是很多。 好吧,現在你已經讓我在電子海灣周圍徘徊了。 Bastages。

[1]文件系統層次結構標準。 https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard

[2]是的,有時候人們仍然會這樣做。 不,我沒有在我的腰帶上戴蘿蔔或洋蔥。


這是一個shell規範,它告訴shell哪個程序可以執行腳本。

#!/usr/bin/env python

解析為Python二進製文件的路徑。


這樣做的主要原因是使腳本跨操作系統環境移植。

例如在mingw下,python腳本使用:

#!/c/python3k/python 

在GNU / Linux發行版下它可以是:

#!/usr/local/bin/python 

要么

#!/usr/bin/python

並且在所有(OS / X)的最佳商用Unix sw / hw系統下,它是:

#!/Applications/MacPython 2.5/python

或在FreeBSD上:

#!/usr/local/bin/python

但是,所有這些差異都可以通過以下方式使腳本在所有人中間移植

#!/usr/bin/env python

這被稱為shebang線 。 正如維基百科條目所解釋的

在計算中,一個shebang(也稱為hashbang,哈希,磅砰,或crunchbang)是指字符“#!” 當它們是解釋器指令中的前兩個字符作為文本文件的第一行時。 在類Unix操作系統中,程序加載器將這兩個字符作為文件是腳本的指示,並嘗試使用文件第一行其餘部分指定的解釋器執行該腳本。

另請參閱Unix FAQ條目

即使在Windows中,shebang行不確定要運行的解釋器,也可以通過在shebang行中指定它們將選項傳遞給解釋器。 我發現在一次性腳本中保留一個通用的shebang行是非常有用的(比如我在回答問題時編寫的腳本),所以我可以在Windows和ArchLinux上快速測試它們。

env實用程序允許您在路徑上調用命令:

剩下的第一個參數指定要調用的程序名稱; 它會根據PATH環境變量進行搜索。 任何剩餘的參數都作為參數傳遞給該程序。





shebang