Blasco
Blasco

Reputation: 1745

What is the advantage of "#!/usr/bin/env python" in the shebang rather than just calling the "#!python" interpreter?

I understand the difference between starting a python script like:

#!/usr/bin/env python

or

#!/usr/bin/python

From what I understood, just executes python as we would do in our shell, so it looks in $PATH. The second one is not a fixed path, which has the inconvenient that in a different system the python interpreter might be located in another path.

My question is, why do we need env? Why can we just do:

#!python

This works perfectly fine in my computer? Is there a reason to prefer calling env?

Upvotes: 3

Views: 7532

Answers (2)

gelonida
gelonida

Reputation: 5640

Short answer: This depends on the shell. in bash #!python will just be ignored and you have to use #!/usr/bin/env python. zsh on the other hand seems to be able to handle #!python.

The long answer (for bash):

let's imagine your python file is named 'tst.py' and has following contents

#!python
import sys
print(sys.executable, sys.version)

then you can always type

python tst.py

The first line is completely irrelevant and is not even looked at.

However if you do following (for example on linux)

chmod +x tst.py
./tst.py

Then the first line is looked at to determine which interpreter shall be used (bash, perl, python, something else?) and here at least for my OS (ubuntu) and my shell (bash) an absolute path is required for the executable name (e.g. /bin/bash, /bin/python, /usr/bin/env)

If I call ./tst.py on my ubuntu machine I get

bash: ./tst.py: python: bad interpreter: No such file or directory

Special case Windows, when typing tst.py or clicking on a python script. If you're on windows, the line is looked at, but even if it is wrong a default python interpreter will be used. On Windows, this line could be used to select explicitly python2 or python3 for example. Windows uses file type associations to determine which executable to call for which suffix. for .py files (python 3.x is installed) this is normally py.exe which is an executable located in the system path, that will just call a python interpreter. depending on installed versions, the shebang line and environment vars, that might indicate a virtualenv

Addendum: The first line is interpreted by the shell or in the windows case by py.exe.

It seems bash requires absolute paths for command, whereas zsh accepts relative paths as well.

So for zsh only

#!python

works perfectly well whereas bash requiers absolute paths and thus the trick with the env command

#!/usr/bin/env python

For scripts that shall be executed by a cronjob it's best to hardcode the path of the python executable as PATH is rather minimalistic for cronjobs, so there it's best to have something like

#!/usr/bin/python3.5

or

#!/home/username/myvirtualenv/bin/python

Upvotes: 9

chepner
chepner

Reputation: 532113

Each Python script is written with a particular version of Python in mind. If the shebang is #!/usr/bin/env python, that puts the version used under the control of the individual caller, whose PATH may not provide the right version.

#!/usr/bin/python is a little better, as it puts the decision in the hands of the script itself. However, the script author doesn't necessarily know where the correction version of Python is on your system, so it still may not work.

The solution is to specify the correct location on your system when you install the module or script. The Python installer (pip, etc) will, at that time, rewrite any shebang containing the word python (#!python being the minimal such shebang) to the path specified by the installer.

Now when you run the script, it will point to the correct path that you have already provided, without being subject to runtime PATH lookup that could choose the wrong version.

Note that #!python is not meant to be used as-is, though for various reasons it might work for you. It's is a means towards making sure the script gets a fixed, absolute path to the correct interpreter. #!/usr/bin/python is also subject to install-time replacement, so may serve as a usable default.

Upvotes: 1

Related Questions