无法使用“#!/ usr / bin / env python”将参数传递给python

Cannot pass an argument to python with “#!/usr/bin/env python”

我需要有一个直接可执行的python脚本,所以我用#!/usr/bin/env python启动了该文件。但是,我也需要无缓冲的输出,所以我尝试了#!/usr/bin/env python -u,但在python -u: no such file or directory中失败了。

我发现#/usr/bin/python -u可以工作,但我需要它让PATH中的python支持虚拟env环境。

我有什么选择?


在某些环境中,env不拆分参数。所以您的env在您的路径中寻找"python-u"。我们可以用sh工作。用以下代码行替换您的shebang,一切都会好起来的。

1
2
3
#!/bin/sh
''''exec python -u --"$0" ${1+"$@"} # '''
# vi: syntax=python

另外,我们不必担心去上海的路,对吧?


最好使用环境变量来启用它。参见python文档:http://docs.python.org/2/using/cmdline.html

对于你的情况:

1
2
export PYTHONUNBUFFERED=1
script.py


在Linux上使用shebang时,解释器名称后面的整个行的其余部分将被解释为单个参数。python -u被传递给env,就好像你输入了:/usr/bin/env 'python -u'一样。/usr/bin/env搜索一个名为python -u的二进制文件,但没有。


将参数传递到shebang行是不标准的,而且正如您所试验的那样,在Linux中不能与env结合使用。使用bash的解决方案是使用内置命令"set"来设置所需的选项。我认为可以用python命令来设置stdin的未缓冲输出。

MY2C


这里有一个/usr/bin/env的脚本替代方案,它允许基于/bin/bash在hash bang行上传递参数,并限制在可执行路径中不允许使用空格。我称之为"envns"(env no spaces):

1
2
3
4
5
6
7
8
9
10
#!/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,下面是您的shebang行:

1
#!/usr/local/bin/envns python -u

在Ubuntu 13.10和Cygwin X64上测试。


这可能有点过时,但env(1)手册告诉人们可以使用"-s"来解决这个问题。

1
#!/usr/bin/env -S python -u

在freebsd上似乎很管用。


这是一个拼凑,需要bash,但它可以工作:

1
2
3
4
5
6
7
#!/bin/bash

python -u <(cat <<"EOF"
# Your script here
print"Hello world"
EOF
)


基于Larry Cai的答案,env允许您直接在命令行中设置变量。也就是说,在python之前,可以用等效的PYTHONUNBUFFERED设置来代替-u

1
#!/usr/bin/env PYTHONUNBUFFERED="YESSSSS" python

在RHEL 6.5上工作。我很肯定,env的特性是关于通用的。


我最近为env的gnu coreutils版本编写了一个补丁来解决这个问题:

http://lists.gnu.org/archive/html/coreutils/2017-05/msg00018.html

如果你有这个,你可以做:

1
#!/usr/bin/env :lang:--foo:bar

env:lang:foo:--bar分成lang字段、foo字段和--bar字段。它将在PATH中搜索解释器lang,然后用参数--foobar调用它,再加上脚本的路径和该脚本的参数。

还有一个特性可以在选项中间传递脚本的名称。假设您想运行lang -f other-arg,然后是其余的参数。有了这个补丁env,它是这样做的:

1
#!/usr/bin/env :lang:-f:{}:other-arg

等价于{}的最左边字段替换为后面的第一个参数,在hash bang调用下,该参数是脚本名。然后删除该参数。

在这里,other-arg可以是lang处理的东西,也可以是脚本处理的东西。

为了更好地理解,请参阅补丁中的众多echo测试案例。

我选择了:字符,因为它是一个现有的分隔符,用于在posix系统上使用PATH。由于env进行PATH搜索,它几乎不可能用于名称中包含冒号的程序。{}标记来自find实用程序,该实用程序使用它来表示将路径插入-exec命令行。