Shell 如何在shebang行中动态选择解释器?

Shell 如何在shebang行中动态选择解释器?,shell,scripting,exec,shebang,Shell,Scripting,Exec,Shebang,我正在尝试编写一个脚本,该脚本从shebang行调用,并根据条件(在我的情况下,基于OS版本)返回正确的解释器,但我不理解它为什么不起作用。 我将试着用一个例子来说明: 可执行文件1:/home/orens/dynamicy\u选择解释器/select\u解释器。sh: #!/usr/bin/env bash echoerr() { echo "$@" 1>&2; } interpreter=`cat /home/orens/dynamically_select_interpre

我正在尝试编写一个脚本,该脚本从shebang行调用,并根据条件(在我的情况下,基于OS版本)返回正确的解释器,但我不理解它为什么不起作用。
我将试着用一个例子来说明:
可执行文件1:/home/orens/dynamicy\u选择解释器/select\u解释器。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脚本执行。第1行正确执行,而第2行出现错误。看起来shebang行被悄悄忽略了(甚至打印到stderr的内容也没有显示在屏幕上)

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

谁能解释一下这种行为或帮我解决它


谢谢

附加重定向是否有效将取决于您的操作系统。您的示例(稍微简化,但想法保持不变)适用于我的Debian安装。但是有些操作系统在解释shebang行时有一些限制,包括对命令长度、命令可能使用的参数数量等的限制。请查看一些示例-它们使用PERL,但实际上尝试与您做相同的事情。sourceforge上有一个名为的项目,可能会有所帮助,但我还没有在实践中对其进行测试,它仍处于alpha版本之前。

请检查:

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

(我的重点)

您的产品线: exec“$解释器”“$@” 不包括要执行的脚本,仅包括参数

尝试: exec“$解释器”$0$@


该脚本只是$@中的第一个成员。但是,我尝试了一下您的建议,但没有成功,因为$0是脚本本身的名称(在本例中选择_解释器.sh)。
#!/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$