Why do people write the #!/usr/bin/env python shebang on the first line of a Python script?
在我看来,没有这一行文件运行的方式是一样的。
如果安装了多个版本的python,那么
在Unix中,一个要解释的可执行文件可以通过在第一行的开头有一个
当然,如果您谈论的是其他平台,则此规则不适用(但"shebang行"不会造成任何伤害,而且如果您将该脚本复制到具有Unix基础的平台(如Linux、Mac等),则会有所帮助)。
这就是所谓的shebang线。正如维基百科的条目所解释的那样:
In computing, a shebang (also called a hashbang, hashpling, pound bang, or crunchbang) refers to the characters"#!" when they are the first two characters in an interpreter directive as the first line of a text file. In a Unix-like operating system, the program loader takes the presence of these two characters as an indication that the file is a script, and tries to execute that script using the interpreter specified by the rest of the first line in the file.
另请参见Unix FAQ条目。
即使在windows上,shebang行不能确定要运行的解释器,也可以通过在shebang行上指定选项来将选项传递给解释器。我发现在一次性脚本中保留一个通用的shebang行很有用(例如,在回答so问题时编写的脚本),这样我就可以在Windows和ArchLinux上快速测试它们。
env实用程序允许您在路径上调用命令:
The first remaining argument specifies the program name to invoke; it is searched for according to the
PATH environment variable. Any remaining arguments are passed as arguments to that program.
在其他答案上做一点扩展,下面是一个小例子,说明如何通过不小心使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $ /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 |
Python2.5中不存在JSON模块。
防止这种问题的一种方法是使用通常与大多数python一起安装的版本化python命令名:
1 2 3 4 | $ cat my_script.py #!/usr/bin/env python2.6 import json print"hello, json" |
如果您只需要区分python 2.x和python 3.x,python 3的最新版本还提供了一个
1 2 3 4 | $ cat my_script.py #!/usr/bin/env python3 import json print("hello, json") |
为了运行python脚本,我们需要告诉shell三件事:
shebang
A common use of the
env command is to launch interpreters, by making
use of the fact that env will search $PATH for the command it is told
to launch. Since the shebang line requires an absolute path to be
specified, and since the location of various interpreters (perl, bash,
python) may vary a lot, it is common to use:
#!/usr/bin/env perl instead of trying to guess whether it is
/bin/perl, /usr/bin/perl, /usr/local/bin/perl, /usr/local/pkg/perl,
/fileserver/usr/bin/perl, or /home/MrDaniel/usr/bin/perl on the user's
system...On the other hand, env is almost always in /usr/bin/env. (Except in
cases when it isn't; some systems might use /bin/env, but that's a
fairly rare occassion and only happens on non-Linux systems.)
也许你的问题是这样的:
如果您想使用:
你根本不需要那条线。系统将调用python,然后python解释器将运行脚本。
但如果您打算使用:
像普通程序或bash脚本一样直接调用它,您需要编写该行来指定运行它的程序所使用的系统,(还需要使用
从技术上讲,在Python中,这只是一个注释行。
仅当从shell(从命令行)运行py脚本时才使用此行。这就是所谓的"shebang!"并且它在各种情况下使用,而不仅仅是与Python脚本一起使用。
在这里,它指示shell启动特定版本的python(以处理文件的其余部分)。
这样做的主要原因是使脚本可以跨操作系统环境移植。
例如,在mingw下,python脚本使用:
1 | #!/c/python3k/python |
在gnu/linux发行版下,它可以是:
1 | #!/usr/local/bin/python |
或
1 | #!/usr/bin/python |
在最好的商用Unix sw/hw系统(OS/X)下,它是:
1 | #!/Applications/MacPython 2.5/python |
或者在FreeBSD上:
1 | #!/usr/local/bin/python |
但是,所有这些差异都可以通过以下方式使脚本在所有方面都可移植:
1 | #!/usr/bin/env python |
Linux内核的
当你在巴什上做的时候:
1 | ./something |
在Linux上,它使用路径
在传递给
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
这将读取文件的第一个字节,并将它们与
如果这是真的,那么行的其余部分将由Linux内核进行分析,这将以路径
1 | /usr/bin/env python /path/to/script.py |
这适用于任何使用
是的,你可以用以下方法做一个无限循环:
1 2 3 4 | printf '#!/a ' | sudo tee /a sudo chmod +x /a /a |
bash识别错误:
1 | -bash: /a: /a: bad interpreter: Too many levels of symbolic links |
如果文件以不同的字节开始,那么
最后,您可以使用
但是,我不认为posix指定了shebangs:https://unix.stackexchange.com/a/346214/32558,尽管它在基本原理部分中提到过,并且形式为"如果系统支持可执行脚本,则可能会发生一些事情"。然而,MacOS和FreeBSD似乎也在实施它。
强调一件大多数人错过的事情可能是有意义的,这可能会妨碍立即理解。当您在终端中键入
hashbang需要一个解释器的完整路径。因此,要直接运行您的python程序,您必须提供到python二进制文件的完整路径,这个路径变化很大,特别是考虑到virtualenv的使用。为了解决可移植性问题,使用了
来自Unix StackExchange的源
建议的方法,在文件中提出:
2.2.2. Executable Python Scripts
On BSD’ish Unix systems, Python scripts can be made directly
executable, like shell scripts, by putting the line
1 #! /usr/bin/env python3.2
来自http://docs.python.org/py3k/tutorial/explorer.html可执行的python脚本
这是一个shell约定,告诉shell哪个程序可以执行脚本。
1 | #!/usr/bin/env python |
解析为python二进制文件的路径。
您可以使用virtualenv尝试此问题
这里是Test.Py
1 2 3 | #! /usr/bin/env python import sys print(sys.version) |
创建虚拟环境
1 2 | virtualenv test2.6 -p /usr/bin/python2.6 virtualenv test2.7 -p /usr/bin/python2.7 |
激活每个环境,然后检查差异
1 2 | echo $PATH ./test.py |
It seems to me like the files run the same without that line.
如果是这样,那么您可能在Windows上运行python程序?Windows不使用该行,而是使用文件扩展名来运行与文件扩展名关联的程序。
但是在2011年,开发了一个"python启动程序"(在某种程度上)来模仿Windows的Linux行为。这仅限于选择运行哪一个python解释器—例如,在安装了这两个解释器的系统上选择python 2和python 3。启动程序可以通过python安装作为
这意味着更多的是历史信息而不是"真实"的答案。
请记住,以前有很多类Unix的操作系统,它们的设计者都有自己的概念,可以把东西放在哪里,有时甚至根本不包括python、perl、bash或其他许多GNU/开源的东西。
对于不同的Linux发行版来说,这甚至是正确的。在Linux上--pre-fhs[1]-您可以在/usr/bin/或/usr/local/bin/中使用python。或者它可能没有安装,所以您构建了自己的并将其放入~/bin
Solaris是我工作过的最糟糕的版本,部分原因是从Berkeley Unix到System V的过渡。你可以在/usr/、/usr/local/、/usr/ucb、/opt/etc中找到一些东西。这可能会导致一些非常长的路径。我对sunfreeware.com上的东西有记忆,在它自己的目录中安装每个包,但我不记得它是否将二进制文件符号链接到/usr/bin中。
哦,有时候/usr/bin在一个NFS服务器上[2]。
因此,开发了
然后你可以写
这一点很重要,因为人们在传递shell脚本(如perl和python),如果您在Red Hat Linux工作站上硬编码/usr/bin/python,它将在SGI上坏掉……嗯,不,我认为irix将python放在了正确的位置。但在SPARC工作站上,它可能根本不会运行。
我想念我的SPARC工作站。但不是很多。好吧,现在你让我在E-Bay上转来转去。私生子。
[1]文件系统层次结构标准。https://en.wikipedia.org/wiki/filesystem_hierarchy_标准
[2]是的,有时人们仍然会做这样的事情。不,我的腰带上既没有萝卜也没有洋葱。
如果您在虚拟环境中运行脚本,例如
请注意,虚拟环境的名称嵌入到Python解释器的路径中。因此,在脚本中硬编码此路径将导致两个问题:
- 如果将脚本上载到存储库,则会强制其他用户使用相同的虚拟环境名称。如果他们首先发现问题的话。
- 即使您在其他虚拟环境中拥有所有必需的包,也无法在多个虚拟环境中运行该脚本。
因此,除乔纳森的回答外,理想的shebang是
它只指定要使用的解释器。要理解这一点,请通过执行
1 2 | #!/usr/bin/env python3 print"test" |
并执行EDOCX1[1]以使脚本可执行。在这之后,当您执行
1 2 3 4 | File"./test.py", line 2 print"test" ^ SyntaxError: Missing parentheses in call to 'print' |
因为python3不支持print运算符。
现在继续,将代码的第一行更改为:
1 | #!/usr/bin/env python2 |
它可以工作,将
考虑到
一些分配暂时与
PEP 394强调了这一点:
In order to tolerate differences across platforms, all new code that
needs to invoke the Python interpreter should not specify python, but
rather should specify either python2 or python3 (or the more specific
python2.x and python3.x versions; see the Migration Notes). This
distinction should be made in shebangs, when invoking from a shell
script, when invoking via the system() call, or when invoking in any
other context.
当有多个版本的python时,它告诉解释器要用哪个版本的python运行程序。
这告诉脚本python目录在哪里!
1 | #! /usr/bin/env python |