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


76

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

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

我有什么选择?


1
您可以看看这个SO问题,以获取有关如何进行无缓冲输出的一些信息。
Mattias Nilsson

Answers:



43

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

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

ps我们不必担心sh的路径,对吗?


2
对于那些想知道它如何工作的人:为什么此代码段起作用?
马丁·彼得

14
至少20年以来,${1+"$@"}黑客可能是不必要的:)
2013年

2
骇客也许是不必要的,但这不会带来任何危害吗?知道这很有趣:-)我今天才了解到它。无论如何,我认为"exec" "python" "-u" "--" "$0" "$@"可能更容易理解-是否存在任何缺陷?(我认为这与1+黑客行为不兼容吗?)
Aaron McDaid 2014年

1
我的方法有一个缺点。如果您想传递一些复杂的信息给bash使用,例如带有嵌套'或的字符串",那么您的方法将更可靠。这是一个有趣的问题!我的也许更容易理解,但您的却更强大。也许您的答案应该说明它必须以开头''''exec,并且字符串必须以结尾# '''(在之前有一个空格#)。只要我们遵守这些规则,并且没有任何多余的三引号''',您的方法就是完美而灵活的。
亚伦·麦克戴德

1
@ user4815162342是有关的更多上下文${1+"$@"}。因此,"$@"在大多数情况下应该可以正常工作。
akhan

16

在Linux上使用shebang时,解释器名称后的其余行将被解释为单个参数。将python -u被传递到env如同您键入:/usr/bin/env 'python -u'。在/usr/bin/env对二进制搜索叫python -u,它没有一个。


13

将参数传递到shebang行不是标准的,并且您已经尝试过将其与Linux中的env结合使用。bash的解决方案是使用内置命令“ set”来设置所需的选项。我认为您可以执行相同的操作以使用python命令设置stdin的无缓冲输出。

my2c


13

这可能有点过时,但是env(1)手册告诉您可以在这种情况下使用'-S'

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

在FreeBSD上似乎工作得很好。


哇,如果能广泛使用,那就太好了,但是在cygwin上还不可用:(
philwalk

6
似乎该-S选项特定于BSD变体,env(1)但很高兴知道
nodakai

3
Linux也已经有了env -S-从coreutils 8.30 1开始(可能需要一些时间才能出现在您附近的发行版中)。与FreeBSD相同的语义env(1)-为良好功能的可移植性而欢呼。
胡安

Solaris(11.3)上也没有运气... :(
Timmah

9

这是替代脚本的脚本/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上测试。


2
这应该捆绑在一起:)
wieczorek1990 2014年

注意:大多数unix-ish#!出于安全原因,实现不允许使用脚本。我很惊讶这对Ubunut 13.10起作用。
胡安

截至2019年1月20日,它也适用于ubuntu 16.04,尚不确定其他人。
philwalk

5

这是一个混战,需要重击,但是它可以工作:

#!/bin/bash

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

1
谢谢,这对我来说很好解决了另一个问题(使用带有参数的mono csharp shell)
IanNorton,2012年

5

依靠Larry Cai的答案,env您可以直接在命令行中设置变量。这意味着-u可以用PYTHONUNBUFFERED之前的等效设置代替python

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

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


3
仅供参考,这在Debian中不起作用。我不确定为什么它不起作用(查看ps输出应该没有任何区别),但是它永远不会返回。在Debian中执行此操作时,还不清楚python本身是否真的在运行。我在一些地方尝试过-与同等命令行相比,绝对无法按预期工作。
MartyMacGyver '16

@MartyMacGyver。很有可能与您env甚至使用的版本有关python
疯狂物理学家,2016年

可能是env的版本,但是到目前为止,它不能与任何现代Debian变体一起使用。在这种情况下,似乎没有在Debian上实际运行Python,这使得它在某些平台和/或配置之外的使用受到限制。
MartyMacGyver '16

-1

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

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 <thecriptname> other-arg,然后运行其余参数。对此进行修补后env,就可以这样完成:

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

等价的最左边的字段被后面{}的第一个参数替换,在哈希爆炸调用下,该参数是脚本名称。然后删除该参数。

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

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

我选择该:字符是因为它是PATHPOSIX系统上使用的现有分隔符。由于envPATH搜索,它是微乎其微不太可能使用其名称中包含冒号的程序。该{}标记来源于find实用程序,它使用它来表示的路径的插入-exec命令行。


1
对于阅读此书并感到充满希望的任何人,该补丁都被放弃了
Alex Miller
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.