【问题标题】:How can I dynamically select the interpreter in the shebang line?如何在 shebang 行中动态选择解释器?
【发布时间】:2013-01-20 18:04:55
【问题描述】:

我正在尝试编写一个脚本,该脚本从 shebang 行调用并根据条件(在我的情况下,基于操作系统版本)返回正确的解释器,但我不明白为什么它不起作用。 我将尝试通过一个示例来澄清:
可执行文件 1:/home/orens/dynamically_select_interpreter/select_interpreter.sh:

#!/usr/bin/env bash
echoerr() { echo "$@" 1>&2; }

interpreter=`cat /home/orens/dynamically_select_interpreter/interpreter`
if [ -z "$interpreter" ]; then
  echoerr "Could not find interpreter!"
  exit 1
fi

echoerr "Found interpreter: $interpreter"

exec "$interpreter" "$@"

此脚本根据某些文件的内容(在本例中为:/usr/bin/python)选择解释器。然后,它通过调用exec 将自己替换为正确的解释器。
从命令行调用它,这就是我得到的:

$ /home/orens/dynamically_select_interpreter/select_interpreter.sh
Found interpreter: /usr/bin/python
Python 2.4.3 (#1, Dec 10 2010, 17:24:35)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-50)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

但是,当我尝试在 shebang 行中使用它时,如下所示:

#!/home/orens/dynamically_select_interpreter/select_interpreter.sh


echo $SHELL # should be an error # LINE 1
import sys; print "HERE"; print sys.version # this is the actual error # LINE 2

脚本作为 shell 脚本而不是 python 脚本执行。 LINE 1 正确执行,而 LINE 2 引发错误。看起来 shebang 行被默默地忽略了(甚至打印到 stderr 也没有显示在屏幕上)。

基本上,我正在尝试与env 做同样的事情,但来自脚本。我想如果我用 C/C++ 编写并编译它,我会得到我想要的,但是由于这个脚本将被用作克服多内核版本情况的工具,我真的希望我的可执行文件是 OS-独立的,我实现这一目标的唯一方法是通过脚本。

任何人都可以解释这种行为或帮助我解决它吗?

谢谢!

【问题讨论】:

    标签: shell scripting exec shebang


    【解决方案1】:

    查看execve man page

    解释器必须是可执行文件的有效路径名本身不是脚本

    (强调我的)

    【讨论】:

      【解决方案2】:

      额外重定向是否有效取决于您的操作系统。您的示例(略微简化,但想法保持不变)适用于我的 Debian 安装。但是某些操作系统在解释 shebang 行的方式上存在限制,包括对命令长度、命令可能采用的参数数量等的限制。查看this discussion 的一些示例 - 他们使用 PERL,但基本上尝试这样做和你一样。 sourceforge 上有一个名为 shebang-wrapper 的项目可能会有所帮助,但我还没有在实践中对其进行测试,它仍处于预 alpha 阶段。

      【讨论】:

        【解决方案3】:

        您的线路: 执行“$解释器”“$@” 不包括要执行的脚本,只包括参数。

        尝试: exec "$interpreter" $0 $@

        #!/bin/bash
        echo "PRE:$0 $@"
        if [ "$1" != "--" ]; then
          i=$1
          exec $i $0 -- $@
        else
          shift; shift
        fi
        echo "POST:$0 $@"
        
        bll-desktop:bll$ ./t.sh /bin/sh b c
        PRE:./t.sh /bin/sh b c
        PRE:./t.sh -- /bin/sh b c
        POST:./t.sh b c
        bll-desktop:bll$ ./t.sh /bin/bash b c
        PRE:./t.sh /bin/bash b c
        PRE:./t.sh -- /bin/bash b c
        POST:./t.sh b c
        bll-desktop:bll$
        

        【讨论】:

        • 脚本只是 $@ 中的第一个成员。但是,我确实尝试了您的建议,但没有成功,因为 $0 是脚本本身的名称(在此示例中为 select_interpreter.sh)。
        猜你喜欢
        • 2018-06-01
        • 1970-01-01
        • 2013-05-06
        • 2020-05-15
        • 1970-01-01
        • 2020-10-12
        • 1970-01-01
        • 2016-11-16
        • 1970-01-01
        相关资源
        最近更新 更多