Ale*_*lli 1034

如果您安装了多个版本的Python,/usr/bin/env将确保使用的解释器是您环境中的第一个$PATH.替代方案是硬编码类似的东西#!/usr/bin/python; 没关系,但不太灵活.

在Unix中,一个可以解释的可执行文件可以通过#!在第一行的开头加上解释器(以及它可能需要的任何标志)来指示要使用的解释器.

当然,如果您正在谈论其他平台,那么这条规则并不适用(但"shebang line"没有任何损害,如果您将该脚本复制到具有 Unix基础的平台,例如Linux,Mac ,将会有所帮助等).

  • 只是补充一下:当你在Unix中运行它时,它适用于可执行文件(`chmod + x myscript.py`),然后直接运行它:`./ myscript.py`,而不仅仅是`python myscript.py`. (251认同)
  • 使用`env`提供了最大的灵活性,用户可以通过更改PATH来选择要使用的解释器.通常这种灵活性并不是必需的,但缺点是linux例如不能在`ps`中使用脚本名称作为进程名称并恢复为"python".例如,在为发行版打包python应用程序时,我建议不要使用`env`. (26认同)
  • [`py` launcher](http://docs.python.org/dev/using/windows.html#python-launcher-for-windows)可以在Windows上使用shebang行.它包含在Python 3.3中或[它可以独立安装](https://bitbucket.org/vinay.sajip/pylauncher). (8认同)
  • 一个重要的警告词,env的返回值最终会到期.如果您运行的是短期流程,则不太可能对您产生影响.但是,我已经让进程死了`/ usr/bin/env:Key已经过了好几个小时了. (5认同)
  • @Aneesh:这适用于UNIX,但不适用于Windows.阅读http://www.python.org/dev/peps/pep-0397/ (3认同)
  • 一般来说,人们没有编辑符号链接的权限,但他们可以控制他们的 $PATH (2认同)
  • @malaverdiere您可以链接到任何说明此过期行为的资源吗?我找不到他们。 (2认同)

Sin*_*nür 256

这被称为shebang线.正如维基百科条目所述:

在计算中,一个shebang(也称为hashbang,hashpling,pound bang或crunchbang)指的是字符"#!" 当它们是解释器指令中的前两个字符作为文本文件的第一行时.在类Unix操作系统中,程序加载器将这两个字符作为文件是脚本的指示,并尝试使用文件中第一行其余部分指定的解释器来执行该脚本.

另请参阅Unix FAQ条目.

即使在Windows上,shebang行也没有确定要运行的解释器,您可以通过在shebang行上指定它们来将选项传递给解释器.我发现在一次性脚本(例如我在回答SO上的问题时写的那些)中保留通用的shebang系列很有用,所以我可以在Windows和ArchLinux上快速测试它们.

ENV工具可以让你的道路上调用命令:

第一个剩下的参数指定要调用的程序名称; 根据PATH环境变量进行搜索.任何剩余的参数都作为参数传递给该程序.

  • 很容易找到谷歌 - 如果知道关键字("shebang线"是必不可少的). (28认同)
  • 实际上,这种解释比我在谷歌检查过的其他参考文献更清晰.获得针对该问题的1段解释总是更好,而不是阅读解决每个潜在用途的整个手册. (13认同)
  • “即使在 Windows 上,shebang 行不能确定要运行的解释器,您也可以通过在 shebang 行中指定选项来将选项传递给解释器。” 那是完全错误的;如果发生这样的事情,那是因为解释器本身正在处理 shebang 行。如果解释器对shebang行没有特殊识别,则不会发生这种情况。Windows 不会对 shebang 行做任何事情。”在这种情况下,您可能描述的是 python 启动器:https://www.python.org/dev/peps/pep-0397/。 (2认同)
  • @树正 请仔细阅读这句话。它所说的既不是你或卡兹认为的那样。例如,Windows 上的“perl”并不关心是否存在“/usr/bin/perl”,而是会关注传递给它的选项。 (2认同)

Ned*_*ily 147

在其他答案上稍微扩展一下,这里有一个小例子,说明你的命令行脚本如何通过不谨慎地使用/usr/bin/envshebang行来解决问题:

$ /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
Run Code Online (Sandbox Code Playgroud)

Python 2.5中不存在json模块.

防止出现此类问题的一种方法是使用通常与大多数Pythons一起安装的版本化python命令名称:

$ cat my_script.py 
#!/usr/bin/env python2.6
import json
print "hello, json"
Run Code Online (Sandbox Code Playgroud)

如果您只需要区分Python 2.x和Python 3.x,最新版本的Python 3也提供了一个python3名称:

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

  • 嗯,这不是我从那篇文章中得到的. (27认同)

Ros*_*one 83

为了运行python脚本,我们需要告诉shell三件事:

  1. 该文件是一个脚本
  2. 我们想要执行哪个解释器脚本
  3. 所述翻译的路径

shebang #!完成了(1.).shebang以a开头,#因为该#字符是许多脚本语言中的注释标记.因此,解释器会自动忽略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系统上.)


小智 43

也许你的问题就是这个意义:

如果你想使用: $python myscript.py

你根本不需要那条线.系统将调用python,然后python interpreter将运行您的脚本.

但是如果你打算使用: $./myscript.py

像普通程序或bash脚本一样直接调用它,你需要编写该行来指定系统运行它的程序,(并使其可执行chmod 755)


mjv*_*mjv 39

从技术上讲,在Python中,这只是一个注释行.

仅当您从shell(从命令行)运行py脚本时才使用此行.这被称为" Shebang!" ,它用于各种情况,而不仅仅是Python脚本.

在这里,它指示shell启动特定版本的Python(以处理文件的其余部分).


小智 38

这样做的主要原因是使脚本可以跨操作系统环境移植.

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

#!/c/python3k/python 
Run Code Online (Sandbox Code Playgroud)

在GNU/Linux发行版下,它是:

#!/usr/local/bin/python 
Run Code Online (Sandbox Code Playgroud)

要么

#!/usr/bin/python
Run Code Online (Sandbox Code Playgroud)

在所有(OS/X)的最佳商业Unix sw/hw系统下,它是:

#!/Applications/MacPython 2.5/python
Run Code Online (Sandbox Code Playgroud)

或者在FreeBSD上:

#!/usr/local/bin/python
Run Code Online (Sandbox Code Playgroud)

但是,所有这些差异可以通过使用以下方式使脚本可移植到所有

#!/usr/bin/env python
Run Code Online (Sandbox Code Playgroud)

  • 在 MacOSX 下,它也是 `/usr/bin/python`。在Linux下,系统安装的Python也几乎可以肯定是`/usr/bin/python`(别的我没见过,没意义)。请注意,可能有些系统没有 `/usr/bin/env`。 (2认同)
  • 如果您使用的是 OSX 并使用 Homebrew 并按照他们的默认安装说明进行操作,它将位于 #!/usr/local/bin/python 下 (2认同)

Cir*_*四事件 37

execLinux内核的系统调用#!本身可以理解shebangs()

当你在bash上做:

./something
Run Code Online (Sandbox Code Playgroud)

在Linux上,它exec使用路径调用系统调用./something.

在传递给的文件中调用内核的这一行exec:https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

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

这将读取文件的第一个字节,并将它们与之进行比较#!.

如果这是真的,那么Linux内核将解析该行的其余部分,这将使用path exec和current文件作为第一个参数进行另一个exec调用:

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Run Code Online (Sandbox Code Playgroud)

这适用于任何/usr/bin/env python用作注释字符的脚本语言.

是的,您可以通过以下方式进行无限循环:

/usr/bin/env python /path/to/script.py
Run Code Online (Sandbox Code Playgroud)

Bash识别错误:

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Run Code Online (Sandbox Code Playgroud)

# 恰好是人类可读的,但这不是必需的.

如果文件以不同的字节开头,那么#!系统调用将使用不同的处理程序.另一个最重要的内置处理程序是ELF可执行文件:https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305,它检查字节exec(也恰好是人类可读的7f 45 4c 46).这将读取ELF文件,将其正确放入内存,然后使用它启动新进程.另请参阅:内核如何获取在linux下运行的可执行二进制文件?

最后,您可以使用该.ELF机制添加自己的shebang处理程序.例如,您可以/bin/ls文件添加自定义处理程序.此机制甚至通过文件扩展名支持处理程序.另一个应用程序是使用QEMU透明地运行不同体系结构的可执行文件.

我不认为POSIX指定shebangs:https://unix.stackexchange.com/a/346214/32558 ,虽然它确实提到了基本原理部分,并且形式为"如果系统支持可执行脚本可能发生".


saa*_*aaj 22

强调一个最错过的东西可能是有道理的,这可能会妨碍立即理解.当您键入python终端时,通常不提供完整路径.相反,可执行文件在PATH环境变量中查找.反过来,当你想直接执行Python程序时/path/to/app.py,必须告诉shell使用什么解释器(通过hashbang,其他贡献者在上面解释的内容).

Hashbang希望有一个翻译的完整路径.因此,要直接运行Python程序,必须提供Python二进制文件的完整路径,这种路径会有很大差异,特别是考虑到使用virtualenv.为了解决可移植性问题,/usr/bin/env使用了技巧.后者最初旨在就地改变环境并在其中运行命令.如果没有提供更改,它会在当前环境中运行命令,这有效地导致相同的PATH查找功能.

来自unix stackexchange的源代码


Fra*_*ger 13

这是一个shell约定,告诉shell哪个程序可以执行脚本.

#!/usr/bin/env python

解析为Python二进制文件的路径.


Grz*_*cki 12

这是建议的方式,在文档中提出:

2.2.2.可执行的Python脚本

在BSD的Unix系统上,Python脚本可以直接执行,就像shell脚本一样,通过放置行

#! /usr/bin/env python3.2
Run Code Online (Sandbox Code Playgroud)

来自http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts


Cra*_*een 9

在我看来,如果没有该行,文件运行相同.

如果是这样,那么也许你在Windows上运行Python程序?Windows不使用该行,而是使用文件扩展名来运行与文件扩展名关联的程序.

然而,在2011年,开发了一个"Python启动器",它(在某种程度上)模仿了Windows的这种Linux行为.这仅限于选择运行哪个Python解释器 - 例如,在安装了两者的系统上选择Python 2和Python 3.启动器可选地安装为py.exePython安装,并且可以与.py文件关联,以便启动器检查该行,然后启动指定的Python解释器版本.

  • 他可能也在使用`$ python myscript.py`. (6认同)

小智 9

您可以使用virtualenv尝试此问题

这是test.py

#! /usr/bin/env python
import sys
print(sys.version)
Run Code Online (Sandbox Code Playgroud)

创建虚拟环境

virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
Run Code Online (Sandbox Code Playgroud)

激活每个环境,然后检查差异

echo $PATH
./test.py
Run Code Online (Sandbox Code Playgroud)


小智 9

它只是指定您要使用的解释器.要理解这一点,请通过终端创建一个文件touch test.py,然后在该文件中键入以下内容:

#!/usr/bin/env python3
print "test"
Run Code Online (Sandbox Code Playgroud)

chmod +x test.py使你的脚本执行.在此之后./test.py你应该收到一个错误说:

  File "./test.py", line 2
    print "test"
               ^
SyntaxError: Missing parentheses in call to 'print'
Run Code Online (Sandbox Code Playgroud)

因为python3不支持print运算符.

现在继续将代码的第一行更改为:

#!/usr/bin/env python2
Run Code Online (Sandbox Code Playgroud)

它会工作,打印test到stdout,因为python2支持打印操作符.所以,现在你已经学会了如何在脚本解释器之间切换.


Pet*_*tro 6

这意味着更多的历史信息而不是"真实的"答案.

请记住,在你有类似的操作系统,其设计师都有自己的地方放东西,有时候想法不包括Python和Perl中,Bash或很多其他的GNU /开源的东西UNIX的批中的一天,回来在所有.

不同的Linux发行版甚至都是如此.在Linux上 - 前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站上它根本不会运行.

我想念我的sparc站.但不是很多.好的,现在你让我在E-Bay上乱逛.Bastages.

[1]文件系统层次结构标准.https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard

[2]是的,有时人们仍然会这样做.不,我的腰带上没有萝卜或洋葱.


Bru*_*yne 5

如果您在虚拟环境中运行脚本venv,那么在执行操作which python时执行venv将显示Python解释器的路径:

~/Envs/venv/bin/python

请注意,虚拟环境名称嵌入在Python解释器的路径中.因此,在脚本中对此路径进行硬编码将导致两个问题:

  • 如果将脚本上载到存储库,则会强制其他用户具有相同的虚拟环境名称.这是他们首先确定问题.
  • 将无法运行在多个虚拟环境中的脚本,即使你有在其他虚拟环境中所有需要的软件包.

因此,为了增加Jonathan的答案,理想的shebang #!/usr/bin/env python不仅仅是跨操作系统的可移植性,而且还是跨虚拟环境的可移植性!


Ros*_*hel 5

该行#!/bin/bash/python3#!/bin/bash/python指定要使用的python 编译器。您可能安装了多个 python 版本。例如,
a.py :

#!/bin/bash/python3
print("Hello World")
Run Code Online (Sandbox Code Playgroud)

是一个 python3 脚本,和
b.py :

#!/bin/bash/python
print "Hello World"
Run Code Online (Sandbox Code Playgroud)

是一个python 2.x脚本
为了运行这个文件./a.py或者./b.py被使用,你需要事先给文件执行权限,否则执行会导致Permission denied错误。
为了给予执行许可,

chmod +x a.py
Run Code Online (Sandbox Code Playgroud)

  • 也许使用:#!/usr/bin/env python3。这样,系统会搜索它的PATH来找到python3,这是一个更漂亮的方法。 (2认同)

归档时间:

查看次数:

681561 次

最近记录:

5 年,11 月 前