【问题标题】:Cannot pass an argument to python with "#!/usr/bin/env python"无法使用“#!/usr/bin/env python”将参数传递给 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,了解有关如何进行无缓冲输出的一些信息。

标签: python arguments shebang


【解决方案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
      猜你喜欢
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      • 2014-04-12
      • 2016-11-23
      • 2022-01-08
      • 2016-04-24
      • 2021-08-18
      • 2011-08-31
      相关资源
      最近更新 更多