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

时间:2013-01-20 18:04:56

标签: shell scripting exec shebang

我正在尝试编写一个从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-独立,我实现这一目标的唯一方法是通过脚本。

有人可以解释这种行为或帮我解决吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

其他重定向是否有效取决于您的操作系统。您的示例(稍微简化,但想法保持不变)适用于我的Debian安装。但是一些操作系统在解释shebang行方面存在局限性,包括命令长度的限制,命令可能采用的参数数量等。查看this discussion的一些例子 - 他们使用PERL但基本上尝试做同样的事情。 sourceforge上有一个名为shebang-wrapper的项目可能会有所帮助,但我没有在实践中对它进行过测试,而且它仍处于pre-alpha状态。

答案 1 :(得分:1)

检查execve man page

  

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

(强调我的)

答案 2 :(得分:0)

你的专栏:     exec“$ interpreter”“$ @” 不包括要执行的脚本,只包括参数。

尝试:     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$