3

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?

4
  • what is your computer? and what do you type to start your script. At least (if I remember well) when I tried this out last (over 20 years ago ;-) ) this didn't work. Commented Oct 11, 2019 at 10:34
  • tried. still doesn't work today on my machine Commented Oct 11, 2019 at 10:40
  • It sounds like you may have been running your script in a way that ignores the shebang line, such as python script.py, or running it on Windows. Commented Oct 11, 2019 at 10:43
  • I would actually prefer not to use env. Using env says to run the script with your preferred Python interpreter, which may not be the interpreter the code requires. #!python, strictly speaking, isn't meant to work as-is. The Python installer (pip, setup.py, etc) will automatically replace that shebang (really, any shebang containing the string python; that's just the minimal example of such a one) with a locally specified absolute path appropriate. That is, it's the job of the installer, not the runner, to make sure the correct interpreter is available. Commented Oct 11, 2019 at 11:29

2 Answers 2

9

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 
Sign up to request clarification or add additional context in comments.

4 Comments

Interesting, in arch it finds the relative path just as if I will execute python from my terminal and #!python works for me
@Blasco Yes Indeed this is interesting. are you using bash or another shell. It might not be the OS, but the shell which reacts differently. Whatever in order to be as interoparable as possible it still seems to be best to use #!/usr/bin/env python`
Makes sense, it's the answer I was looking for, I thought it might work with all shells. I'm using zsh.
I add this to my answer as answers are more presistent than comments
1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.