I'm in a bit of an interesting situation where I have a Python script that can theoretically be run by a variety of users with a variety of environments (and PATHs) and on a variety of Linux systems. I want this script to be executable on as many of these as possible without artificial restrictions. Here are some known setups:
- Python 2.6 is the system Python version, so python, python2, and python2.6 all exist in /usr/bin (and are equivalent).
- Python 2.6 is the system Python version, as above, but Python 2.7 is installed alongside it as python2.7.
- Python 2.4 is the system Python version, which my script does not support. In /usr/bin we have python, python2, and python2.4 which are equivalent, and python2.5, which the script supports.
I want to run the same executable python script on all three of these. It would be nice if it tried to use /usr/bin/python2.7 first, if it exists, then fall back to /usr/bin/python2.6, then fall back to /usr/bin/python2.5, then simply error out if none of those were present. I'm not too hung up on it using the most recent 2.x possible, though, as long as it's able to find one of the correct interpreters if present.
My first inclination was to change the shebang line from:
#!/usr/bin/python
to
#!/usr/bin/python2.[5-7]
since this works fine in bash. But running the script gives:
/usr/bin/python2.[5-7]: bad interpreter: No such file or directory
Okay, so I try the following, which also works in bash:
#!/bin/bash -c /usr/bin/python2.[5-7]
But again, this fails with:
/bin/bash: - : invalid option
Okay, obviously I could just write a separate shell script that finds the correct interpreter and runs the python script using whatever interpreter it found. I'd just find it a hassle to distribute two files where one should suffice as long as it's run with the most up-to-date python 2 interpreter installed. Asking people to invoke the interpreter explicitly (e.g., $ python2.5 script.py
) is not an option. Relying on the user's PATH being set up a certain way is also not an option.
Edit:
Version checking within the Python script is not going to work since I'm using the "with" statement which exists as of Python 2.6 (and can be used in 2.5 with from __future__ import with_statement
). This causes the script to fail immediately with a user-unfriendly SyntaxError, and prevents me from ever having an opportunity to check the version first and emit an appropriate error.
Example: (try this with a Python interpreter less than 2.6)
#!/usr/bin/env python
import sys
print "You'll never see this!"
sys.exit()
with open('/dev/null', 'w') as out:
out.write('something')
import sys; sys.version_info()
to check if the user has the required python version../script.py
) would cause python2.4 to execute it, which would cause your code to detect that it was the wrong version (and quit, presumably). But there's a perfectly good python2.5 that could have been used as the interpreter instead!exec
it if so, otherwise print an error.execve
). The arguments are string literals, no globbing, no regexps. That's it. Even if the first arg is "/bin/bash" and the second options ("-c ...") those options are not parsed by a shell. They are handed untreated to the bash executable, which is why you get those errors. Plus, the shebang only works if it is at the beginining. So you are out of luck here, I'm afraid (short of a script which finds a python interpreter and feeds it a HERE doc, which sounds like an awful mess).