Make Linux/Unix Script Portable With #!/usr/bin/env As a Shebang

You may notice that most shell and Perl script starts with the following line:

#!/bin/bash

OR

#!/usr/bin/perl

Let us find out why is it a good idea to use #!/usr/bin/env bash instead of #!/bin/bash as shebang?



ADVERTISEMENTS



#!/usr/bin/env As a Shebang

The #! is called a shebang. It consists of a number sign and an exclamation point character (#!), followed by the full path to the interpreter such as /bin/bash. All scripts under Linux, *BSD, macOS, and Unix-like system execute using the interpreter specified on a first line. However, there is a small problem. BASH or Perl is not always in the same location (PATH) such as /bin/bash or /usr/bin/perl. If you want to make sure that script is portable across different UNIX like operating systems you need to use /usr/bin/env command as shebang.



Make Linux/Unix Script Portable With #!/usr/bin/env As a Shebang

The env command allows to run a program in a modified environment. First, find line

#!/bin/bash

Replace with

#!/usr/bin/env bash

For example here is a small bash shell script:

#!/usr/bin/env bash x=5 y=10 echo "$x and $y"

The advantage of #!/usr/bin/env bash is that it will use whatever bash executable appears first in the running user’s $PATH variable. If you have two version of bash installed as follows and PATH set to /home/vivek/bin:/usr/local/bin:/usr/bin:/bin:/usr/games/bin:/bin:/usr/bin, than bash4 will execute the script:

/bin/bash #

# /usr/local/bin/bash #

Using env in the shebang of a script

env is a shell command for Unix-like operating systems. We can use it for various purposes. For example:

Display a list of environment variables

Run another command in a modified environment

Add or remove variables

Change the value of existing variables

To show current environment variables defined by your shell, run env command:

env

We can filter out infromation using the grep command/egrep command as follows:

env | grep HOME

env | egrep 'HOME|USER|VERSION|SHELL|PWD'

SHELL=/bin/bash GNOME_SHELL_SESSION_MODE=ubuntu PWD=/tmp HOME=/home/vivek USERNAME=vivek VTE_VERSION=6003 USER=vivek OLDPWD=/tmp

Let us see some more examples.

Perl example

#!/usr/bin/env perl use warnings; print "Hello " x 5; print "\

";

Python2.x example:

#!/usr/bin/env python x=10 y=20 z=x+y print z

Another example with python3:

#!/usr/bin/env python3 import boto3 t = boto3.resource('s3') for b in t.buckets.all(): print(b.name)

Is env always located at /usr/bin/env

You can use the type command or command command to locate exact path for the env command:

type env

command -V env

Sample outputs:

env is /usr/bin/env

Some info from various *nix systems:

OS env path OpenBSD /usr/bin/env FreeBSD /usr/bin/env Debian /usr/bin/env Ubuntu /usr/bin/env CentOS /usr/bin/env macOS /usr/bin/env SUSE /usr/bin/env RHEL /usr/bin/env NetBSD /usr/bin/env Solaris /usr/bin/env

Use shellcheck

ShellCheck is a static analysis tool for shell scripts. One can use it to finds bugs in your shell scripts. It is written in Haskell. You can find warnings and suggestions for bash/sh shell scripts with this tool. Let us see how to install and use ShellCheck on a Linux or Unix-like system to enhance your shell scripts, avoid errors and productivity.

Conclusion

I just made my Linux/Unix script portable with #!/usr/bin/env . The env-mechanism is hugely enhancing convenience, and almost all Unix like systems today provide /usr/bin/env. I regular use FreeBSD, CentOS/RHEL/Ubuntu/Debian/SUSE Linux, macOS, and OpenBSD and all of them provided /usr/bin/env by default. Now you do not have to search for a program via the PATH environment variable. It makes the script more portable. Also, note that it is not a foolproof method. Always make sure you have /usr/bin/env exists or use a soft link/symbolic link to point it to correct path for env command. Moreover, your work or script looks more professional with this simple hack. See env command man page (documentation) or type the following man command:

$ man bash

$ man env