Search code examples
pythonshebang

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?


Solution

  • 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