Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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.

share|improve this question
add comment

1 Answer

up vote 6 down vote accepted

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
share|improve this answer
    
For the zsh-specific workaround, I prefer the following myself [ "x$ZSH_VERSION" = "x" ] && exec zsh -f "$0" "$@" –  huyz May 10 '11 at 6:55
    
Thanks for the research. I didn't know that ` #! /usr/bin/env POSIXLY_CORRECT=1 bash` would work. –  huyz May 10 '11 at 6:57
1  
I guess there is no single "general solution" that no one else can offer. So I'll accept your answer. Hopefully someday Linux gets with the program. –  huyz Jul 5 '11 at 6:33
    
#! /usr/bin/env POSIXLY_CORRECT=1 bash doesn't work as it is as though you wrote /usr/bin/env "POSIXLY_CORRECT=1 bash" script at the shell. –  r3m0t Apr 4 '13 at 20:03
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.