Suppose I have an executable script, test.sh as follows
#!/bin/bash
readlink /proc/$$/exe
When I run the above script as
./test.sh, then I know that bash shell executes the script. Then the output of above script is
$ ./test.sh
/bin/bash
If I run the above script as follows
$ /bin/csh test.sh
Which shell will execute the script -
csh(specified in the command line) or
bash(specified in the shebang)?
The output of the the above command is
/bin/csh.
So why does
/bin/csh execute the script instead of
/bin/bash specified in the script?
Here is the answer,
Whenever a shell script is executed, a new shell(process) is spawned(forked) and the commands in the scripts are executed. The child shell becomes the parent process of commands in the script.
The shebang, #!, is used by the exec() family of functions to determine whether the file to be executed is a binary or script. If the shebang(#!) is present, then exec() will run the executable specified after the shebang - in the above case it is /bin/bash. she-bang is actually a two byte magic number that designates a file type. Immediately following the she-bang(#!) is the path name - this is the path to the program that interprets the commands in the script whether it be a shell, programming language or a utility. This command interpreter then executes the commands in the script starting at the top(following the shebang #! line), ignoring commands.
Now if you run the script by specifying the shell in the command line, like /bin/csh test.sh, the exec() will execute the shell interpreter, /bin/csh specified in the command line instead of looking into the script for shell interpreter specified in shebang line.