Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a Python script that need to be run with a particular python installation. Is there a way to craft a shebang so that it runs with $FOO/bar/MyCustomPython?

share|improve this question
add comment

5 Answers

up vote 13 down vote accepted

The shebang line is very limited. Under many unix variants (including Linux), you can have only two words: a command and a single argument. There is also often a length limitation.

The general solution is to write a small shell wrapper. Name the Python script foo.py, and put the shell script next to foo.py and call it foo. This approach doesn't require any particular header on the Python script.

#!/bin/sh
exec "$FOO/bar/MyCustomPython" "$0.py" "$@"

Another tempting approach is to write a wrapper script like the one above, and put #!/path/to/wrapper/script as the shebang line on the Python script. However, most unices don't support chaining of shebang scripts, so this won't work.

If MyCustomPython was in the $PATH, you could use env to look it up:

#!/usr/bin/env MyCustomPython
import …

Yet another approach is to arrange for the script to be both a valid shell script (which loads the right Python interpreter on itself) and a valid script in the target language (here Python). This requires that you find a way to write such a dual-language script for your target language. In Perl, this is known as if $running_under_some_shell.

#!/bin/sh
eval 'exec "$FOO/bar/MyCustomPerl" -wS $0 ${1+"$@"}'
    if $running_under_some_shell;
use …

Here's one way to achieve the same effect in Python. In the shell, "true" is the true utility, which ignores its arguments (two single-character strings : and ') and returns a true value. In Python, "true" is a string which is true when interpreted as a boolean, so this is an if instruction that's always true and executes a string literal.

#!/bin/sh
if "true" : '''\'
then
exec "$FOO/bar/MyCustomPython" "$0" "$@"
exit 127
fi
'''
import …

Rosetta code has such dual-language scripts in several other languages.

share|improve this answer
1  
@Chris: everything is inside single quotes. Please explain… –  Stéphane Gimenez Sep 17 '11 at 1:17
    
Thanks. I was looking for a single file solution. –  eric.frederich Sep 19 '11 at 13:08
add comment

You can either use the absolute path to the custom python installation, or you can put it in your $PATH and use #!/usr/bin/env [command]. Otherwise, write a wrapper for it and use exec to replace the process image, as an example:

#!/bin/bash
exec "$ENV/python" "$@"
share|improve this answer
add comment

Shebang lines do not undergo variable expansion, so you cannot use $FOO/MyCustomPython as it would search for an executable named dollar-F-O-O-...

An alternative is to have your shebang point to a shell script as the interpreter, and this shell script can then use environment variables to locate the correct one and exec it.

Example: create a mypython.sh script in /usr/local/bin (or any other directory on your $PATH), with the following content:

#! /bin/sh
PYTHON="$FOO/bar/MyCustomPython"
exec "$PYTHON" "$@"

then you can use this shebang line to have a Python script executed through MyCustomPython via mypython.sh:

#!/usr/bin/env mypython.sh
share|improve this answer
2  
Use $python, not $PYTHON -- by convention, we capitalize environment variables (PAGER, EDITOR, SHELL ... $PYTHON in your script is not an environment variable) and internal shell variables (BASH_VERSION, RANDOM, ...). All other variable names should contain at least one lowercase letter. This convention avoids accidentally overriding environmental and internal variables. Also, don't use extensions for your scripts. Scripts define new commands that you can run, and commands are generally not given extensions. –  Chris Down Sep 16 '11 at 18:20
add comment

First, determine how your version of Python is different from the standard Python already installed (for example, an additional module) and then at the start of the program 'switch' how the Python is called:

#!/usr/bin/python
import os
import sys
try:
    import MyCustomModule
except ImportError:
    # only need to use expandvar if you know the string below has an envvar
    custprog = os.path.expandvar("$FOO/bar/MyCustomPython")
    os.execv(custprog, sys.argv) # call alternate python with the same arguments
    raise SystemExit('could not call %s' % custprog)
# if we get here, then we have the correct python interpreter

This should allow the program to be called by any other instance of Python. I do something similar for an instance with built-in sql library that cannot be imported as a module in the system's python.

share|improve this answer
add comment

If you can replace $FOO in $FOO/bar/MyCustomPython with concrete path options, you can tell the env shebang line where to look up your custom Python version by directly setting a custom PATH in it.

#!/usr/bin/env PATH="/path1/to/MyCustomPython:/path2/to/MyCustomPython" python

Edit: Seems to work only without quotes around the PATH value assignment:

#!/usr/bin/env PATH=/path1/to/MyCustomPython:/path2/to/MyCustomPython python
share|improve this answer
2  
Beware that this doesn't work on all unix variants (e.g. not on Linux). And you're removing all the existing directories from the path, which is likely to cause problems down the line. –  Gilles Sep 17 '11 at 20:52
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.