Shell Scripting Shebang

How to use a shebang to automatically look for the interpreter binary in the users PATH environment variable.

28 views

Created: 2023-09-23 00:00

#!/usr/bin/env bash

This is the #! shebang used to specify the location of the bash binary. The /usr/bin/env command is making the system look for the specified binary in the users $PATH, and it is therefore considered more compatible than simply hard-coding a path for the bash binary.

Hard-coding the path for an interpreter binary in a shebang is done like this:

#!/bin/bash

However, for scripts you plan on distributing, it may be better use the #!/usr/bin/env shebang, as it can make your script more compatible with the end user's environment.

Also, rather than simply specifying sh, it is better to specifically define the bash binary as the interpreter for your script. This is because sh could mean something different than what you expect depending on system. E.g. (sh = default system shell). On some systems, it will be a symbolic link pointing to whatever is the default in that system. Most of us probably expect /bin/bash, but sh could refer to /bin/zsh or /bin/dash.

You can test the output of env by typing it into your terminal and hitting enter:

ubuntu@homecomputer:~$ env

Output:

SHELL=/bin/bash
PWD=/home/ubuntu
LOGNAME=ubuntu
XDG_SESSION_TYPE=tty
MOTD_SHOWN=pam
HOME=/home/ubuntu
LANG=en_US.UTF-8

As you can see, env gives you the environment variables for the current user that executes it. Using it in a shebang will make the system search the $PATH of the user for the specified interpreter (typically bash). You can do a echo $PATH to view its contents:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/var/lib/snapd/snap/bin:/snap/bin:/var/lib/snapd/snap/bin

Where exactly binaries are kept depends on the system, but for GNU/Linux distributions, they will usually be kept in standard locations such as:

It could still break

While the #!/usr/bin/env [interpreter] shebang is preffered by many of us for scripts we distribute, it is important to keep in mind that it could still result in unexpected behaviour, although it is very unlikely on modern systems.

1. It could be that a user only installed a given binary in /usr/local/bin, but does not have this location added to their $PATH.

2. It is not possible to pass arguments to the interpreter you specify this way, but that is usually not a problem anyway.

3. It might not work for cron jobs, because the expected $PATH can be limited to /usr/bin and /bin. However, for most cron jobs you probably want to specify the exact location of the binary anyway, because if you have administrative access and know the system, why would you use #!/usr/bin/env in the first place?

Note. It is also possible to specify a "shebang" for other scripting languages. E.g. PHP or Python if they are used as CLI scripts.

Adding a custom environment variable

You can verify this further by adding a custom variable to your environment:

ubuntu@homecomputer:~$ export sayhallo="hallo world"
ubuntu@homecomputer:~$ echo $sayhallo

Output:

hallo world

When subsequently running env, the variable you just added will also be shown:

# ...
sayhallo=hallo world

Links

  1. Bash (Archlinux wiki) - wiki.archlinux.org
  2. nixos.wiki - nixos.wiki

Tell us what you think:

  1. How to read user input from shell scripts using the read command.
  2. How to use the tilde character in bash scripts, having it point to the users home directory as expected.
  3. Article trying to explain why you may not want to use bash for larger scripting work.
  4. How to make a simple bash script that watches files for changes.
  5. How to generate, and compare hashes from terminal using bash and PHP scripts in Linux.

More in: Bash Tutorials