Frage

I am trying to write a script which is called from the shebang line and returns the right interpreter based on a condition (in my case, based on OS version) and I can't understand why it doesn't work.
I'll try to clarify by an example:
Executable file 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" "$@"

This script selects the interpreter based on some file's contents (in this case the contents are: /usr/bin/python). Then, it replaces itself with the right interpreter by calling exec.
Calling it from command line, this is what I get:

$ /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.
>>>

However, when I try to use it inside a shebang line, like this:

#!/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

the script is executed as a shell script instead of a python script. LINE 1 is executed properly while LINE 2 raises errors. It looks like the shebang line is silently ignored (and even the print to stderr doesn't show on screen).

Basically, I am trying to do the same as env, but from a script. I guess that if I write it in C/C++ and compile I'll get what I want, but since this script will be used as a tool to overcome multiple-kernel-versions situation, I would really like my executable to be OS-independant and my only way to achieve this is by a script.

Can anybody explain this behaviour or help me solve it?

Thanks!

War es hilfreich?

Lösung 2

Whether the additional redirection works will depend on your OS. Your example (slightly simplified, but the idea stays the same) works on my Debian installation. But some operating systems have limitations in how they interpret the shebang line, including limitations to the length of the command, the number of arguments the command may take etc. Check out this discussion for some examples - they use PERL but essentially try to do the same thing as you. There is a project on sourceforge called shebang-wrapper which might be of help, but I haven't tested it in practice and it's still in pre-alpha.

Andere Tipps

Check the execve man page:

The interpreter must be a valid pathname for an executable which is not itself a script.

(emphasis mine)

Your line: exec "$interpreter" "$@" does not include the script to be executed, only the arguments.

Try: 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$
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top