Search code examples
pythonpython-3.xshebang

What shebang should I use to consistently point to python3?


I have a script which uses the shebang #!/usr/bin/env python. It works great on machines where Python 3 is the only version available, but on the machines which have both Python 2 and Python 3, it runs the script with Python 2.

If I modify the shebang to be #!/usr/bin/env python3, it would work on the machines with Python 2 and Python 3, but on the machines which have only Python 3, it would fail with “No such file or directory” error.

One solution is to create an alias alias python=python3.

Are there other solutions to have a same shebang working uniformly on every machine?


Solution

  • Unfortunately, there is no universally working way of doing this that would work across any and all up front unknown Linux hosts and you are largely left at the mercy of distro maintainers and local host configuration.

    alias won't help, because interpreter specified by #! handled by the kernel and /usr/bin/env it will exec in this case does not know about aliases of your shell.

    When using env, you could make sure that the name following env is first found and means what you want it to mean by:

    • making sure all hosts are setup the same way in that respect (expected packaged are installed or at least symlinks are created)
    • having user specific construct for execution of your script, such as:
      mkdir /tmp/bin
      ln -s /usr/bin/python /tmp/bin/python3
      PATH="/tmp/bin:${PATH}" ./myscript.py
      

    But none of this is really great and ultimately what you've asked for.

    Your interpreter (this is harder than it may sound though, interpreter resolution code is quite simple; where to put it, how to call it for kernel to find and use it) could also be a simple shell script that tries to figure it out that you pack with your python code, but any option you look at isn't really great I am afraid.

    There is a PEP-394 for that which suggested / expected on U*X-like system:

    • you get python for python2
    • and python3 for python3

    But it recognizes this has never been entirely consistently applied... and also not as useful in 2020:

    However, these recommendations implicitly assumed that Python 2 would always be available. As Python 2 is nearing its end of life in 2020 (PEP 373, PEP 404), distributions are making Python 2 optional or removing it entirely. This means either removing the python command or switching it to invoke Python 3. Some distributors also decided that their users were better served by ignoring the PEP's original recommendations, and provided system administrators with the freedom to configure their systems based on the needs of their particular environment.

    TL;DR unfortunately there is no way that universally works and compensates for decisions of various distro and even individual host maintainers. :(

    I would most likely opt to stick with #!/usr/bin/env python3 (which has so far been the recommended naming) and add a README that explains the prerequisites and how to setup the host just to be sure.


    For the sake of completeness I should add, the PEP does make a recommendation in this regard: setup and use virtual environment or use a (third party) environment manager. However the way I read the question: "Portable interpreter specification that does not make any assumptions about nor poses any (additional) requirements to target host configuration", this would then not fit the bill and would not mean a substantial improvement over saying: make sure you have python3 executable in the search path and create a symlink if not.