Wrapping dynamic languages in shell without an extra script
March 25th, 2008
There are situations where, if you want a Python, PERL, PHP, etc script to be portable among a few different servers, it makes sense to wrap the script in shell. A few years ago I was trying to use the Python cx_Oracle module. This module is a wrapper for the native Oracle database driver. However, it requires the driver library directory be in the LD_LIBRARY_PATH environment variable.
No problem I thought. I’ll use the os.environ dict to set the variable. Example script:
$ cat python-only.sh
#!/usr/bin/python
import sys, os
sys.path.append("/usr/local/lib/python2.4/site-packages/")
if not os.environ.has_key('LD_LIBRARY_PATH'):
os.environ['LD_LIBRARY_PATH'] = "/home/noland/oracle-lib"
else:
os.environ['LD_LIBRARY_PATH'] = "/home/noland/oracle-lib:" + os.environ['LD_LIBRARY_PATH']
print "LD_LIBRARY_PATH looks OK in Python: LD_LIBRARY_PATH = ", os.environ['LD_LIBRARY_PATH']
os.system('echo LD_LIBRARY_PATH looks OK via os.system: LD_LIBRARY_PATH = $LD_LIBRARY_PATH')
try:
import cx_Oracle
print "Imported cx_Oracle! LD_LIBRARY_PATH was set correctly."
except ImportError, e:
print "Woops, LD_LIBRARY_PATH was not set correctly: ", e
This method does not work:
$ ./python-only.sh LD_LIBRARY_PATH looks OK in Python: LD_LIBRARY_PATH = /home/noland/oracle-lib LD_LIBRARY_PATH looks OK via os.system: LD_LIBRARY_PATH = /home/noland/oracle-lib Woops, LD_LIBRARY_PATH was not set correctly: libclntsh.so.10.1: cannot open shared object file: No such file or directory
This seems to be a common problem. However, when I was dealing with this a few years ago, I could not find a good resource on Google. I bite the bullet and wrote a separate shell script wrapper - hating invocation of the shell script. However, there is absolutely no reason I needed a separate shell script. I could have embedded the Python within a shell script. Example:
$ cat python-and-bash.sh
#/bin/bash
export LD_LIBRARY_PATH=/home/noland/oracle-lib:$LD_LIBRARY_PATH
/usr/bin/python<<END_OF_PYTHON
import sys
sys.path.append("/usr/local/lib/python2.4/site-packages/")
try:
import cx_Oracle
print "Imported cx_Oracle! LD_LIBRARY_PATH was set correctly."
except ImportError, e:
print "Woops, LD_LIBRARY_PATH was not set correctly: ", e
END_OF_PYTHON
Ahh, much better:
$ ./python-and-bash.sh Imported cx_Oracle! LD_LIBRARY_PATH was set correctly.
Of course I could have just set this variable in my profile. However, this creates an additional external dependency - which is what I was trying to avoid.


March 26th, 2008 at 2:54 am
Hmmm,
I never thought of that.
Instead I used bashes multiline single quoted string feature to wrap my python source that I used double quoted strings in:
Python -c ‘
# python “source” “”"here”"”
‘
Your way seems better, although how do you add extra command line options?
- Paddy.
March 27th, 2008 at 6:45 am
I had an another idea of using a shebang line like the following:
#!/usr/bin/env LD_LIBRARY_PATH=/home/noland/oracle-lib:$LD_LIBRARY_PATH /usr/bin/python
But it doesn’t work, because:
a. shebang lines are seperated into TWO (and only two) arguments —
1. the program to run (/usr/bin/env)
2. the rest of the line, given as a single argument the to program.
So in this case, the shell (or whomever is dealing with these shebang lines, I think you wrote on that once) tries to find a command named “LD_LIBRARY_PATH=/home/noland/oracle-lib:$LD_LIBRARY_PATH /usr/bin/python”, which doesn’t exist.
b. I’m not sure that variable substitution would have worked inside the shebang line, even if we solve somehow problem a. If you need to add something to an existing environment variable, you must have variable substitution, I guess.
March 27th, 2008 at 9:54 am
@Paddy3118,
> although how do you add extra command line options?