Objective Criteria/Requirements:
In determining whether to use an absolute or logical (/usr/bin/env
) path to an interpreter in a she-bang, there are (2) key considerations:
a) The interpreter can be found on target system
b) The correct version of interpreter can be found on target system
If we AGREE that "b)" is desirable, we also agree that:
c) It's preferable our scripts fail rather than execute using an incorrect interpreter version and potentially achieve inconsistent results.
If we DON'T AGREE that "b)" matters, then any interpreter found will suffice.
Testing:
Since using a logical path- /usr/bin/env
to the interpreter in the she-bang is the most extensible solution allowing the same script to execute successfully on target hosts with different paths to the same interpreter, we'll test it- using Python due to its' popularity- to see if it meets our criteria.
- Does
/usr/bin/env
live in a predictable, consistent location on POPULAR (not "every") Operating Systems? Yes:
- RHEL 7.5
- Ubuntu 18.04
- Raspbian 10 ("Buster")
- OSX 10.15.02
- Below Python script executed both inside and outside of virtual envelopes (Pipenv used) during tests:
#!/usr/bin/env pythonX.x
import sys
print(sys.version)
print('Hello, world!')
- The she-bang in the script was toggled by Python version number desired (all installed on same host):
- #!/usr/bin/env python2
- #!/usr/bin/env python2.7
- #!/usr/bin/env python3
- #!/usr/bin/env python3.5
- #!/usr/bin/env python3.6
- #!/usr/bin/env python3.7
Expected results: that print(sys.version)
= env pythonX.x
. Each time ./test1.py
was executed using a different installed Python version, the correct version specified in the she-bang was printed.
Testing Notes:
- Tests were exclusively limited to Python
- Perl: Like Python- MUST live in
/usr/bin
according to the FHS
- I've not tried every possible combination on every possible number of Linuxy/Unixy Operating System and version of each Operating System.
Conclusion:
Although it's TRUE that #!/usr/bin/env python
will use the first version of Python it finds in the user's Path, we can moderate this behaviour by specifying a version number such as #!/usr/bin/env pythonX.x
. Indeed, developers don't care which interpreter is found "first", all they care about is that their code is executed using the specified interpreter they know to be compatible with their code to ensure consistent results- wherever that may live in the filesystem...
In terms of portability/flexibility, using a logical- /usr/bin/env
- rather than absolute path not only meets requirements a), b) & c) from my testing with different versions of Python, but also has the benefit of fuzzy-logic finding the same version interpreter even if they live at different paths on different Operating Systems. And although MOST distros respect the FHS, not all do.
So where a script will FAIL if binary lives in different absolute path then specified in shebang, the same script using a logical path SUCCEEDS as it keeps going until it finds a match, thereby offering greater reliability & extensibility across platforms.
does using the .bash extension actually invoke bash or does it depend
on system config / 1st shebang line.
If you do not use an interpreter explicitly, then the interpreter being invoked is determined by the shebang
used in the script. If you use an interpreter specifically then the interpreter doesn't care what extension you give for your script. However, the extension exists to make it very obvious for others what kind of script it is.
[sreeraj@server ~]$ cat ./ext.py
#!/bin/bash
echo "Hi. I am a bash script"
See, .py
extension to the bash script does not make it a python script.
[sreeraj@server ~]$ python ./ext.py
File "./ext.py", line 2
echo "Hi. I am a bash script"
^
SyntaxError: invalid syntax
Its always a bash
script.
[sreeraj@server ~]$ ./ext.py
Hi. I am a bash script
Best Answer
The
#!/usr/bin/env bash
results in the script using whatever bash is found first in$PATH
.While it is common for bash to be located at
/bin/bash
. There are cases where it is not (different operating systems). Another potential use is when there are multiple bash shells installed (newer version at an alternate location like/usr/local/bin/bash
).Doing
#!/usr/bin/env bash
just takes advantage of a behavior of theenv
utility.The
env
utility is normally used for manipulating the environment when calling a program (for example;env -i someprog
to wipe the environment clean). However by providing no arguments other than the program to execute, it results in executing the specified program as found in$PATH
.Note that there are both advantages and disadvantages to doing this.
The advantages are as mentioned earlier, in that it makes the script portable if bash is installed in a different location, or if
/bin/bash
is too old to support things the script is trying to do.The disadvantage is that you can get unpredictable behavior. Since you're at the mercy of the user's
$PATH
, it can result in the script being run with a version of bash that has different behavior than what the script expects.