Shebang line limitations

Here at Zenoss, we had a need to run Python in a modified environment. A script was written (by a third party) wrapping the python binary, and became `which python`:

. /path/to/
/path/to/.python.bin "$@"

This replaced the binary as the path to the interpreter.

Then we tested it. Most of the scripts in $ZENHOME/bin are shell scripts that call Python scripts elsewhere, but a few, including most of the ones laid down by Zope during the mkzopeinstance installation step, are straight up Python scripts with the shebang #!/usr/local/zenoss/bin/python ($ZENHOME in this case is /usr/local/zenoss; distutils does a string replace of shebang lines during the install-scripts step). When we tried to execute these scripts with the new Python wrapper in place, we got things like:

runtests: line 3: import: command not found<br />from: can't read /var/mail/subprocess<br />runtests: line 5: import: command not found<br />runtests: line 6: import: command not found<br />runtests: line 8: ZENHOME: command not found<br />runtests: line 9: syntax error near unexpected token `('<br />runtests: line 9: `ZOPEHOME = os.environ.get('ZOPEHOME', ZENHOME)'

/bin/sh was trying to interpret the script. When we executed the shebang on the command line, we were thrown into the interpreter, so it wasn't a simple path problem. When we asked around, one of our more experienced developers knew the cause immediately: the shebang line has to point to a binary.

We figured we were pretty much sunk; among other things, the script set the LD_LIBRARY_PATH against which that Python binary had been compiled (the idea was that the binary could be portable that way), so we couldn't call it directly and set environment variables via Python, for example. Eventually we came up with a hacky but totally workable solution:

#!/usr/bin/env /path/to/my/wrapper/python

env is a command meant to interact with environment variables and run other commands in modified environments. If you don't give it a modified environment, it'll use the current one, which makes it basically a pass-through; on the command line, env python and python are synonymous. /usr/bin/env is, needless to say, a binary file.

I don't know why the shebang line has this limitation; presumably it's some security issue. But there's the solution, if you absolutely have to circumvent it: call your shell script through env.


Post a Comment