Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

shebang script interpreter from shell variable

Tags:

bash

shell

I have a number of scripts which need to specify the python binary which runs them:

#! /home/nargle/python/bin/python2.6

I need to adapt these scripts to work at two different sites. Lots of tools are installed in different places, so at new site 2 the script needs to start with:

#! /user/nargle/python/bin/python2.6
..

I want to replace directly-quoted paths with environment variables which are set differently for each site. What I would like is for this to work:

#! $MY_PYTHON_PATH

but it doesn't! I am slightly hazy on where to research this. Is it the executing shell (be it bash, csh or whatever) which detects the '#!' at the start of a script (be it bash, python or whatever) and fires up the interpreter/shell to run it?

I feel that there must be some way to do this. Please advise!

Oh yes, there is one more constraint: we cannot use the path for this. This may seem like a stupid restriction but this is for a large environment with many users

The environment is RHEL 5.7.

EDIT It has been suggested to use a shell script and that is the current plan: it works fine:

 $MY_PYTHON_PATH some_script file.py $@

The problem is really that we have lots of people using the python files, and lots of automated tests which need to changed. If it has to be done it has to be done but I if possible I want to minimise the impact of a change of working practice for scores of people.

EDIT It would also be possible to have a link in a location which is the same on both systems, and which links to the real binary in a different target on each system. This is quite feasible but seems kind of messy: we use the linux 'modules' package to setup environment variables for many tools and it would be nice if we could take the python path from our modulefiles.

EDIT It isn't the answer but this feels like the kind of evil hack I was looking for: http://docs.nscl.msu.edu/daq/bluebook/html/x3237.html .. see "Example 4-2. #! lines for bash and for tclsh"

EDIT I hoped this might work but it didn't:

!# /usr/bin/env PATH=$PATH:$MY_PYTHON_PATH python2.6
like image 600
PatB Avatar asked Jan 24 '13 10:01

PatB


2 Answers

The common solution is to change the shebang to

#!/usr/bin/env python2.6

Then, just arrange your $PATH to point to the right python2.6 on each machine.

like image 163
choroba Avatar answered Oct 29 '22 03:10

choroba


Write a wrapper shell script. If you have script.py, write a script.py.sh with the following content:

#!/bin/bash
PYTHON_SCRIPT=$( echo "$0" | sed -e 's/\.sh$//' )
exec $MY_PYTHON_PATH $PYTHON_SCRIPT "$@"

Disclaimer: This isn't tested, just wrote it off the top of my head.

Now just set up your MY_PYTHON_PATH on each machine, and call script.py.sh instead of script.py.

Summary This solution is only second-best, since it requires a lot of script calls to be changed from script.py to script.py.sh, something that should be avoided if at all possible.


Alternative

Use env to call a python-finder script, which just calls the python binary contained in $MY_PYTHON_PATH. The python-finder script has to be in the same location on both machines, use symlinks if necessary.

#!/usr/bin/env /usr/local/bin/python-finder.sh

The contents of python-finder.sh:

#!/bin/bash
exec $MY_PYTHON_PATH "$@"

This works because for interpreter scripts (those starting with a shebang) execve calls the interpreter and passes the filename to env, which in turn passes it on to the command it calls.

like image 41
Perleone Avatar answered Oct 29 '22 04:10

Perleone