#!/usr/bin/env Interpreter Arguments — portable scripts with arguments for the interpreter

Posted on

Problem :

Because interpreters such as zsh, bash, python, perl may be located in different places on the filesystem, scripts often have a shebang that uses env for portability, e.g. #!/usr/bin/env zsh. However, as http://en.wikipedia.org/wiki/Shebang_(Unix)#Portability explains, many systems including Linux don’t allow the passing of arguments to the interpreter.

Often, I’d like to do something like #!/usr/bin/env zsh -f to prevent my script to ever read my ~/.zshenv, or I’d like to do #!/usr/bin/env perl -w, etc. This works on OS X, but not on Linux.

What is the workaround for that? Can I have the best of both worlds: portability and arguments for the interpreter? If possible, give a general workaround that works for all interpreters, not just zsh.

Solution :

Here’s an inline solution to work around the portability problem for ZSH.

#! /bin/sh

if [ -z "$IN_ZSH" ]; then
  export IN_ZSH=1
  exec zsh -f "$0" "$@"
fi

## Your ZSH script here

Some other methods to try include

  • Passing env variables via /usr/bin/env which modify the behavior the same as --options such as doing
    #! /usr/bin/env POSIXLY_CORRECT=1 bash
  • Using clever commenting tricks, such as how this script starts out using SH but invokes TCL on the same script
    #! /bin/sh
    # 
    TCLBIN=/usr/bin/tclsh; 
    exec $TCLBIN "$0" "$@"
    # Execute the rest via tclsh
    set argc
  • Setting the option once in the interpreter, if the --options being passed in do not affect the load behavior
    #! /usr/bin/env bash
    # Exit if any error detected
    set -e
  • For perl, if you’re able to use newer versions, this may work in lieu of -w:
    #! /usr/bin/env perl
    use warnings;
  • Using a bootstrap invoke.sh script instead of /usr/bin/env to use your PATH, calling with /path/to/invoke.sh script with your script starting with #! zsh -f
    #! /bin/sh

    SCRIPT=$1
    shift 1
    cmd=`sed -n -e 's:#! ?::' -e '1p' $SCRIPT`
    exec $cmd $SCRIPT

Leave a Reply

Your email address will not be published. Required fields are marked *