There are several shells in my Linux, like bash, sh, zsh...
And I know there are at least 3 ways to specify a shell to execute my shell scripts:
#!/usr/bash
sh MyScripts.sh
$SHELL
(say, SHELL=zsh
), and execute the script like ./MyScripts.sh
So, my big question is when there is conflict between these three ways, which rule has the highest priority? Which the lowest one?
And what if I do sh MyScripts.zsh
? You see, the suffix and binary don't match.
File names are just file names. They can be anything, except zero byte and /
. Suffix is just for humans. They can be anything. They do not matter on Linux.
When you type cmd ./filename
then shell executes command cmd
with argument ./filename
. It does not matter if cmd
is python
, zsh
, bash
or wc
, it is getting executed with the first argument set to ./filename
. Now what the program does with the string ./filename
is up to the program. sh
is a program, that when it has one argument that does not start with a leading -
, then that program sh
reads that a file named as the first argument and interprets its content. So sh ./filename
executes ./filename
as a sh
script.
"Interpreter" is a type of programs, that are meant to interpret the content of a file in a specific programming language. For example program python
is a Python programming language interpreter. sh
meant to be an interpreter for POSIX-compatible Shell programming language. Etc.
When you type ./filename
in shell, then shell (or kernel) checks if the file has executable permissions set. If it does, it reads two first bytes of the file. If the two first bytes of the file are #!
, then it reads to the end of the first line of the file. Then the first line is interpreted as the command to run the filename with. So when you do ./filename
and you have #!anything_here
then the shell runs anything_here ./filename
.
SHELL
is unrelated here, it's sometimes not even set. It's usually a variable that is set to the path to the current interpreter. So if you want to run a file with the same interpreter as currently running, you would type $SHELL ./filename
, so shell can expand variable SHELL
and run the program the same as current interpreter you are running on.