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

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:
- /usr/bin
- /usr/local/bin
- /bin
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
- Bash (Archlinux wiki) - wiki.archlinux.org
- nixos.wiki - nixos.wiki
Tell us what you think: