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

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