You will often encounter shell scripts starting with #! /bin/bash, #! is called a shebang or hashbang. shebang plays an important role in shell scripting, especially when dealing with different types of shells.

In this tutorial we will explain what shebang is, how it plays a role in shell scripting. And how to specify an interpreter for shell scripts. We will use the two shells, bash and zsh, for comparison. All shell programming tutorials can be used in many Linux distributions such as Ubuntu, Debian, Fedora, Redhat, CentOS, Suse, Arch, Gentoo etc.

shebang in shell scripts

shebang is written with the well # and the exclamation mark ! . This character combination has a special meaning when used in the first line of a script. It is used to specify the interpreter that will run the specified script by default.

Thus, if the first line of a script is ! /bin/bash, this means that the interpreter should be the bash shell; if the first line is ! /bin/zsh, this means that the interpreter to be used is the Z shell.

Because # is used for comments in shell scripts, but in this case #! has a special meaning.

The role of shebang in shell scripts

shebang is not mandatory for scripts. If you write a simple script like this.

1
echo "Namaste, folks!"

and grant it execute permission and use the . operator, it will be run by the shell you used when you logged in, i.e. you are currently using the shell. so why do shell scripts include the #!/bin/bash line?

Because there are a variety of shells available for Linux and UNIX systems. While most of these shells have a common syntax, they do have different syntax or ways of handling different options.

This is why it becomes important to specify the correct shell interpreter in your scripts, otherwise certain scripts may produce different results when run in different shells. Let me show you this with a simple example.

The importance of specifying a shell interpreter using shebang

I have written a sample shell script containing an array of Linux distributions. The second element of the distribution array is then printed on the second line of the script.

1
2
distros=("Ubuntu" "Fedora" "SUSE" "Debian")
echo "Distro at index 2 is: ${distros[2]}"

At this point there is no shebang line added to specify any shell interpreter. This means that when I execute this script, it will be run by the default shell (in my case bash, echo $0 to print the shell currently in use).

1
2
myfreax.com@swift:~$ echo $0
bash

The output is as follows.

1
2
myfreax.com@swift:~$ ./arrays.sh 
Distro at index 2 is: SUSE

Print SUSE at index 2, because in Bash and many other programming and scripting languages the array index starts at 0. But this is not the case in the Z shell. In the Z shell, the array index starts at 1.

We can install the Z shell on our own system, Linux allows multiple shells to exist at the same time, now we will add the shebang line to the script to specify that the default shell for the script is run by the Z shell.

1
2
3
4
#!/bin/zsh

distros=("Ubuntu" "Fedora" "SUSE" "Debian")
echo "Distro at index 2 is: ${distros[2]}"

The output is as follows.

1
2
myfreax.com@swift:~$ ./arrays.sh 
Distro at index 2 is: Fedora

Now you should notice the difference. It’s the same script, but with the shebang line added but different.

This is why it is important to specify the correct shell interpreter with the shebang operator. As a system administrator, you may write shell scripts and remember a particular shell, whether it is bash, ksh or zsh, but you cannot be sure that the system on which the script will be run has the same default shell as your system.

If you specify a shell explicitly, shebang will be ignored

because shebang specifies the shell interpreter that will run the script. However, you can explicitly specify the shell to run the script, but in this case the shebang line will be ignored.

1
myfreax.com@swift:~$ bash ./arrays.sh

How does shebang work?

When you use shebang in the first line of a script, you are telling the shell to run the script using the specified command. This is like, #!/bin/zsh is the equivalent of.

1
/bin/zsh script_name

You already know that if the first line of the script starts with shebang, this means that you specified the shell interpreter. This is only partially correct. But that’s what shebang is for. Sometimes the shebang line doesn’t have to have a shell executable. It can be anything.

For example, I replace #!/bin/zsh instead of #!/bin/cat and the cat command will become the shell’s interpreter.

1
2
3
4
#!/bin/cat

distros=("Ubuntu" "Fedora" "SUSE" "Debian")
echo "Distro at index 2 is: ${distros[2]}"

This means that the script will now be run with the cat command and the contents of the script will be displayed. It will output all the contents of the script. As long as it points to an executable command, it will work. If you put in some random command that doesn’t exist, it will throw an error. I changed the shebang line to read

1
#!/home/myfreax

Obviously, it does not point to any command executable, so it will raise an interpreter error.

1
2
3
4
5
6
7
myfreax.com@swift:~$ cat arrays.sh 
#!/home/www.myfreax.com

distros=("Ubuntu" "Fedora" "SUSE" "Debian")
echo "Distro at index 2 is: ${distros[2]}"
myfreax.com@swift:~$ ./arrays.sh 
bash: ./arrays.sh: /home/abhishek: bad interpreter: Permission denied

Conclusion

At this point, you have the role of the shebang line in the script. And you can specify any command in the shebang line.