Portable shebang
UNIX scripts usually start with a shebang (short for sharp-bang) line which specifies which interpreter to use to execute the script file. A typical shebang for a bourne shell script looks as follows.
#! /bin/sh
echo “Script is executed by Bourne shell located at /bin/sh”
The problem is that the location of the interpreter may be located on different locations in different UNIX variants. For instance bash
is located in /usr/local/bin/bash
on most xBSD UNIXes (but not MacOS) but in /bin/bash
on most Linuxes and MacOS. It should also be noted that the shebang doesn’t use the PATH
environment variable so full path to the interpreter is necessary.
So how to make portable shebangs in UNIX scripts. I have identified a number of solutions.
Use env
command
UNIX env
command is used to view and change environment variables, but it can also be used to locate a executable using PATH
environment variable. The following shebang will execute the script using bash
if bash
is available in PATH
.
#! /usr/bin/env bash
echo “Script is executed by Bash shell if it can be located in PATH”
The idea is that the location of /usr/bin/env
is more standardized between UNIXes than e.g. bash
. If env
for some reason isn’t located under /usr/bin
you may want to symlink to it to accomplish that.
ln –s /path/to/env /usr/bin/env
Convert shebangs during install
Some argue that shell scripts should be adapted to each UNIX during install of the script. An install script could be used to replace the shebang of other scripts contained in the program adapting to the target UNIX.
Of course the install script itself must be able to run on each OS. One solution is to use Bourne shell language for the install script as the location of Bourne shell is more common between different UNIX variants. Alternatively you may use the solution described above for the install script only.
#! /bin/sh
# Use e.g. sed to update shebangs of other scripts in this application
Symlink to interpreter location
A last alternative is to create symbolic links to assumed locations of interpreters used in the program. This could also be done in a install script discussed above. When e.g. scripts assume /bin/bash
as location for bash
we must create a symlink to actual location in environments where this does not apply.
ln –s /usr/local/bin/bash /bin/bash
Other options
Other options I have come across is to use getconf PATH
to look for standard shell. Another is to use command –v bash
for locating the full path to bash
. This is recommended solution by POSIX, but I havn’t studied them further as they doesn’t seem to be very common.
References
- http://www.cyberciti.biz/tips/finding-bash-perl-python-portably-using-env.html
- http://perfec.to/shebang/
- http://www.in-ulm.de/~mascheck/various/shebang/
- env(1)
- execve(2)
- getconf(1)