Points to ponder

  • The interpreter named on the shebang line must be an absolute path. The kernel does not search PATH when executing the interpreter. The only portable interpreters are /bin/sh and /bin/csh. csh does not have an equivalent to "$@", so it must be /bin/sh.
  • The shebang line is limited to 32 characters on some systems.
  • env is located in /bin on some systems and /usr/bin on others.
  • /bin/sh does not search PATH when called upon to execute a script on the command line.
  • On some systems the text after #!/bin/sh is split into arguments, and on some systems, all the text after the whitespace is sent as one single argument.

For more details and background information, see The #! magic.

perl:

#! /bin/sh
#!perl
eval 'exec perl -x -wS $0 ${1+"$@"}'
  if 0;

bash:

#! /bin/sh
[ "$BASH" ] || exec bash `which $0` ${1+"$@"}

ksh:

#! /bin/sh
(whence cd) >/dev/null 2>&1 || exec ksh `which $0` ${1+"$@"}

nawk:

#!/bin/sh
false {
    eval "AWK=`(nawk 'BEGIN{print \"nawk\"}') 2>/dev/null||echo awk`"
    eval "exec \$AWK -f `which $0` ${1+\"$@\"}"
}

Anybody know a simpler one? This one only works with nawk, but will work whether it is named “nawk” or “awk”. The original awk does not like single token patterns, and expects BEGIN to be the first pattern if it is used. The shell interprets the “{” as an argument to false, then procedes to the two evals. The first eval figures out which awk to execute. When nawk sees this construct, it interprets it as a pattern-action. The pattern “false” is an expression which evaluates to 0, meaning it will never match. The text within { and } is the action. This action is parsed by nawk, so it must fit nawk’s lexical rules, which is why eval and quoted strings are used. This is less than optimal because it fires up nawk just to print a single line. Also, unless nawk is somehow optimized to remove dead code, the comparison against false must be done on every input line.