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.

3 Responses to “Wrapping dynamic languages in shell without an extra script”

  1. Paddy3118 Says:

    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.

  2. dubek Says:

    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.

  3. Brock Noland Says:

    @Paddy3118,

    > although how do you add extra command line options?

    $ ./python-and-bash-with-options.sh
    ['ARG!']
    noland@swat:~$ cat python-and-bash-with-options.sh
    #!/bin/bash
    /usr/bin/python - 'ARG!'< 
    

    @dubek,

    That’s a novel idea and I think it would work if env supported it, whether variables are expanded or not.

    > I’m not sure that variable substitution would have worked inside the shebang line, even if we solve somehow problem

    If I remember correctly, that entire line gets passed into the kernel.

    I am going to look at this some more.
    Brock

Leave a Reply

If Wordpress eats your comment (shell output, loops, ex..) email the text to me.