1. Overview
Shebang is a character sequence consisting of a hash sign and an exclamation mark(#!). In Linux, Solaris, macOS, BSD, and other Unix-based systems, it’s commonly used as the first line in script files to specify an interpreter that executes commands present in the file.
In this tutorial, we’ll find out the differences between #!/usr/bin/bash and #!/usr/bin/env bash. Also, we’ll discuss their advantages and disadvantages.
2. Setup
Using a text editor like nano, let’s create and open an executable file sample.sh:
$ nano sample.sh
Then, we add this content to the file:
#!/usr/bin/bash
echo "Baeldung is Awesome!"
We also need to make the script file executable using the chmod command:
$ chmod u+x sample.sh
Here, the u+x flag grants execution(x) access to the current user(u).
We’ll use this file throughout this tutorial for testing the behavior of #!/usr/bin/bash and #!/usr/bin/env bash shebang lines.
3. Using #!/usr/bin/bash
#!/usr/bin/bash is a shebang line used in script files to set bash, present in the ‘/bin’ directory, as the default shell for executing commands present in the file.**
It defines an absolute path /usr/bin/bash to the Bash shell. This is usually the default location of the Bash shell in almost all Unix-based operating systems.
To find out where Bash is located in our system, we can use the which command:
$ which bash
/usr/bin/bash
Since the sample.sh we created already includes this shebang line, let’s run it:
$ ./sample.sh
Baeldung is Awesome!
We can also use the #!/usr/bin/bash shebang line to pass extra parameters to the shell interpreter:
#!/usr/bin/bash -r
This shebang line is used to execute commands with the Bash interpreter. The -r option enables restricted shell mode.
The #!/usr/bin/bash shebang is recommended when we want to accurately point to an interpreter’s absolute path. It also has relatively high security, and we can pass additional parameters.
On the downside, it has poor portability because different systems can have interpreters installed in different locations. It can also be hard to remember the absolute path of all interpreters, especially in systems that have several interpreters installed, including python, zsh, csh, ksh, sh, and tcsh.
4. Using #!/usr/bin/env bash
As we mentioned earlier,#!/usr/bin/env bash is also a shebang line used in script files to execute commands with the Bash shell.
It uses the env command to display the environment variables present in the system and then execute commands with the defined interpreter.
The env command works by instructing the system to look for the specified interpreter through the $PATH variable and use the first occurrence found. It’s located in the “/usr/bin/env” directory in Unix-based systems.
We can verify its location on our system using the which command:
$ which env
/usr/bin/env
Let’s use env to display all current environment variables defined by the shell:
$ env
SHELL=/bin/bash
SESSION_MANAGER=local/user-PC:@/tmp/.ICE-unix/2839,unix/user-HP-Pavilion-g6-Notebook-PC:/tmp/.ICE-unix/2839
QT_ACCESSIBILITY=1
COLORTERM=truecolor
...truncated
Next, let’s use grep to display $PATH from the env command:
$ env | grep PATH
WINDOWPATH=2
PATH=/home/username/.rbenv/shims:/home/username/.rbenv/bin:/home/username/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
From the output above, we can see that $PATH contains symlinks to /bin and other directories, separated by colons.
To test this shebang line, let’s first modify the first line of the sample.sh file:
#!/usr/bin/env bash
Then, we can execute the script file:
$ ./sample.sh
Baeldung is Awesome!
Running script files through /usr/bin/env has the advantage of automatically searching for the default version of the interpreter in the current environment. This way, we don’t need to search for it in a specific location in the system, as the paths may be different in other systems.
We can also specify a version of the interpreter to be used. Here’s an example format for specifying the Bash interpreter version:
#!/usr/bin/env bashX.x
The #!/usr/bin/env bash shebang offers more portability because we don’t have to write the absolute path to an interpreter.
However, it doesn’t support multiple parameters. This is because the declared interpreter and its option are parsed as one argument.
Additionally, it can be error-prone in instances where we have more than one version of an interpreter in our environment because it uses the first instance of bash found in $PATH.
5. Comparison
Here’s a table showing the comparisons between these shebang lines:
#!/usr/bin/bash
#!/usr/bin/env bash
Offers more security
Offers more portability
More specific, since we have to declare the exact path to an interpreter
Automatically searches for the first occurrence of an interpreter in the environment
Can support extra parameters passed after the declaration of the interpreter
Cannot support extra parameters because the system reads them as a single command
6. Conclusion
In this article, we’ve explored the differences between #!/usr/bin/bash and #!/usr/bin/env bash shebang lines. We’ve also looked at their advantages and disadvantages.
We can use either of them to execute commands in shell scripts with the Bash shell or any other shell. However, it’s recommended to use #!/usr/bin/bash when security is a priority and #!/usr/bin/env bash if we’re looking for portability.