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

Posted

技术标签:

【中文标题】无法使用“#!/usr/bin/env python”将参数传递给 python【英文标题】:Cannot pass an argument to python with "#!/usr/bin/env python" 【发布时间】:2011-03-19 09:40:50 【问题描述】:

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

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

我有什么选择?

【问题讨论】:

您可以查看SO question,了解有关如何进行无缓冲输出的一些信息。 【参考方案1】:

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

my2c

【讨论】:

【参考方案2】:

这是一个杂牌,需要 bash,但它可以工作:

#!/bin/bash

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

【讨论】:

谢谢,这对我解决另一个问题很有效(使用带参数的单声道 csharp shell)【参考方案3】:

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

【讨论】:

【参考方案4】:

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

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

附言我们不必担心 sh 的路径,对吧?

【讨论】:

对于那些想知道这是如何工作的人:Why does this snippet work? $1+"$@" hack 可能至少有 20 年没有必要了 :) 黑客也许是不必要的,但它不会造成任何伤害,不是吗?知道它很有趣 :-) 我今天才知道它。无论如何,我认为"exec" "python" "-u" "--" "$0" "$@" 可能更容易理解——它有什么缺陷吗? (我认为它与1+ hack 不兼容?) 我的方法有个缺点。如果您想将一些复杂的东西传递给 bash,例如嵌套了 '" 的字符串,那么您的方法更可靠。这是一个有趣的问题!我的可能更容易理解,但你的更健壮。也许您的答案应该澄清它必须以''''exec 开头,并且字符串必须以# ''' 结尾(# 之前有一个空格)。只要我们遵循这些规则,并且没有任何额外的三引号''',您的方法就是完美且灵活的。 @user4815162342 Here 是$1+"$@" 的更多上下文。所以"$@" 在大多数情况下应该可以自己正常工作。【参考方案5】:

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

你的情况:

export PYTHONUNBUFFERED=1
script.py

【讨论】:

每次重启时都需要这样做吗? @dan:当你在同一个 shell 中时不会。在export 一个变量之后,它将保持设置,直到您覆盖或unset【参考方案6】:

这可能有点过时,但 env(1) 手册告诉人们可以在这种情况下使用“-S”

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

它似乎在 FreeBSD 上运行良好。

【讨论】:

哇,如果这能广泛使用就好了,但在 cygwin 上也不可用:( 似乎 -S 选项特定于 env(1) 的 BSD 变体,但很高兴知道 Linux 现在也有 env -S - 从 coreutils 8.30 1 开始(可能需要一段时间才能出现在您附近的发行版上)。与 FreeBSD 的 env(1) 语义相同 - 万岁,因为良好的功能可移植性。 在 Solaris (11.3) 上也没有运气... :( #!/usr/bin/env -S node --inspect - WORKS!【参考方案7】:

这里是/usr/bin/env 的替代脚本,它允许在哈希爆炸行上传递参数,基于/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,这里是你的 shebang 行:

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

在 Ubuntu 13.10 和 cygwin x64 上测试。

【讨论】:

这应该是捆绑的:) 注意:大多数 unix-ish #!出于安全原因,实现不允许使用脚本。我很惊讶这适用于 Ubunut 13.10。 截至 2019-01-20 也适用于 ubuntu 16.04,不确定其他版本。【参考方案8】:

基于 Larry Cai 的回答,env 允许您直接在命令行中设置变量。这意味着-u 可以替换为python 之前的等效PYTHONUNBUFFERED 设置:

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

适用于 RHEL 6.5。我很确定env 的功能几乎是通用的。

【讨论】:

仅供参考,这在 Debian 中不起作用。我不确定为什么它不起作用(查看ps 输出应该没有任何区别)但它永远不会返回。当您在 Debian 中执行此操作时,python 本身是否真的在运行并不是很清楚。我在几个地方试过这个 - 与等效的命令行相比,绝对不能按预期工作。 @MartyMacGyver。很可能与您使用的env 甚至python 的版本有关。 可能是 env 的版本,但到目前为止它不适用于任何现代 Debian 变体。 Python 似乎并没有真正在 Debian 上运行在这种情况下,这使得它在某些平台和/或配置之外的使用受到限制。【参考方案9】:

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

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

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

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

env:lang:foo:--bar 拆分为langfoo--bar 字段。它将在PATH 中搜索解释器lang,然后使用参数--foobar 以及脚本的路径和该脚本的参数调用它。

还有一个功能可以在选项中间传递脚本的名称。假设您要运行lang -f &lt;thecriptname&gt; other-arg,然后是剩余的参数。使用这个补丁env,它是这样完成的:

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

相当于 的最左边字段被替换为后面的第一个参数,在哈希爆炸调用下,它是脚本名称。然后删除该参数。

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

为了更好地理解,请查看补丁中的大量 echo 测试用例。

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

【讨论】:

对于任何阅读本文并感到充满希望的人,补丁was abandoned。

以上是关于无法使用“#!/usr/bin/env python”将参数传递给 python的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 StorageClass 配置卷 - 无法获取存储帐户的存储密钥

Worklight Studio 和本地开发,有时无法使用 Java 类,有时无法使用 HTML 文件

ADB无法使用解决办法

Ubuntu 80端口无法使用-非root用户无法使用1024以下端口

无法在 SQL Server 视图中使用工作查询:“IS”无法识别“>”无法识别

LINUX下的mail\mailx为啥无法使用外部SMTP发邮件