我需要一个可直接执行的Python脚本,因此我在文件开头加入了#!/usr/bin/env python
。但是,我还需要无缓冲输出,所以我尝试了#!/usr/bin/env python -u
,但会出现python -u: no such file or directory
的错误。
我发现#/usr/bin/python -u
可以工作,但我需要让python
在PATH
中支持虚拟env
环境。
我的选择有哪些?
我需要一个可直接执行的Python脚本,因此我在文件开头加入了#!/usr/bin/env python
。但是,我还需要无缓冲输出,所以我尝试了#!/usr/bin/env python -u
,但会出现python -u: no such file or directory
的错误。
我发现#/usr/bin/python -u
可以工作,但我需要让python
在PATH
中支持虚拟env
环境。
我的选择有哪些?
在一些环境中,env不会分割参数。
因此你的env正在路径中查找python -u
。
我们可以使用sh来解决这个问题。
将你的shebang替换为以下代码行,一切都会正常。
#!/bin/sh
''''exec python -u -- "$0" ${1+"$@"} # '''
# vi: syntax=python
顺便说一下,我们不需要担心sh的路径,对吧?
${1+"$@"}
hack」可能已经20年没必要使用了 :) 该技巧的具体内容可参考链接:http://www.perl.com/doc/FMTEYEWTK/sh_dollar_at - user4815162342"exec" "python" "-u" "--" "$0" "$@"
可能更容易理解 - 它有什么缺陷吗?(我认为它与 1+
hack 不兼容?) - Aaron McDaid'
或"
字符串,那么你的方法更可靠。这是一个有趣的问题!也许我的方法更容易理解,但你的方法更健壮。也许你的答案应该澄清必须以''''exec
开头,并且字符串必须以# '''
结尾(在#
之前有一个空格)。只要我们遵循这些规则,而且没有任何额外的三重引号'''
,你的方法就是完美和灵活的。 - Aaron McDaid这可能有点过时,但 env(1) 手册告诉我们可以在那种情况下使用“-S”
#!/usr/bin/env -S python -u
它似乎在FreeBSD上表现得相当不错。
-S
选项是针对BSD变种的env(1)
,但了解这一点很好。 - nodakaienv -S
了,自从coreutils 8.30以后就有了[1](可能需要一些时间才能在您的发行版上出现)。与FreeBSD的env(1)
具有相同的语义-值得称赞的好功能的可移植性。 - Juan最好使用环境变量来启用此功能。请参阅Python文档:http://docs.python.org/2/using/cmdline.html
对于您的情况:
export PYTHONUNBUFFERED=1
script.py
export
导出变量后,它将保持设置,直到您覆盖或使用 unset
取消设置。 - artu-hnrq当你在Linux上使用shebang时,解释器名称后的整个剩余行被解释为单个参数。 python -u
就像你打了 /usr/bin/env 'python -u'
一样传递给了 env
。 /usr/bin/env
查找名为 python -u
的二进制文件,但实际上不存在这样一个文件。
在Linux中,将参数传递给shebang行并不是标准的做法,而且在你尝试使用env时无法正常工作。对于bash,解决方法是使用内置命令“set”来设置所需的选项。我认为你可以使用Python命令来设置stdin的非缓冲输出,方法类似。
以上为个人意见。
这里提供了一个替代 /usr/bin/env
的脚本,可以在 hash-bang 行上传递参数,基于 /bin/bash
并且限制执行路径中不允许有空格。它被称作 "envns" (env No Spaces)。
#!/bin/bash
ARGS=( $1 ) # separate $1 into multiple space-delimited arguments.
shift # consume $1
PROG=`which ${ARGS[0]}`
unset ARGS[0] # discard executable name
ARGS+=( "$@" ) # remainder of arguments preserved "as-is".
exec $PROG "${ARGS[@]}"
#!/usr/local/bin/envns python -u
测试过在Ubuntu 13.10和cygwin x64上运行。
#!/bin/bash
python -u <(cat <<"EOF"
# Your script here
print "Hello world"
EOF
)
延续Larry Cai的回答,env
允许您直接在命令行中设置变量。这意味着可以在执行python
命令之前使用等效的PYTHONUNBUFFERED
设置来替换-u
:
#!/usr/bin/env PYTHONUNBUFFERED="YESSSSS" python
适用于RHEL 6.5。我相信env
功能几乎是通用的。
ps
输出没有任何区别),但它从来没有返回过。如果在 Debian 中这样做,很不清楚 Python 是否真的在运行。我尝试在几个地方使用了此方法 - 与等效命令行相比,明显不能正常工作。 - MartyMacGyverenv
或甚至python
版本有关。 - Mad Physicist我最近为GNU Coreutils版本的env
编写了一个补丁来解决这个问题:
http://lists.gnu.org/archive/html/coreutils/2017-05/msg00018.html
如果你有这个,你可以做到以下事情:#!/usr/bin/env :lang:--foo:bar
env
将:lang:foo:--bar
分成lang
、foo
和--bar
字段。 它将在PATH
中搜索解释器lang
,然后使用参数--foo
、bar
以及脚本路径和该脚本的参数来调用它。
还有一个特性,可以在选项中间传递脚本的名称。假设您想运行lang -f <thecriptname> other-arg
,然后是其余参数。 使用这个修补的env
就像这样:
#!/usr/bin/env :lang:-f:{}:other-arg
最左边的字段相当于 {}
,将被替换为其后的第一个参数,在 hash bang 调用下,该参数是脚本名称。然后删除该参数。
在这里,other-arg
可能是由 lang
处理的内容,也可能是由脚本处理的内容。
要更好地理解,请参见补丁中众多的 echo
测试案例。
我选择了 :
字符,因为它是 POSIX 系统上用于 PATH
的现有分隔符。由于 env
进行 PATH
搜索,因此几乎不可能用于包含冒号的程序的名称。 {}
标记来自于 find
实用程序,它用于表示将路径插入到 -exec
命令行中。