Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I have two shebang lines, one for python and one for python3?

I have a script that I am running on multiple Linux OSs. The shebang line of my script is:

#!/usr/bin/python

When I came across CentOS 8, this doesn't work as I get the following: "-bash: ./sysinfo-snapshot.py: /usr/bin/python: bad interpreter: No such file or directory"

And as a workaround I can change the shebang line to

#!/usr/bin/python3

and this would 100% solve the issue.

However, what I'm looking for is to have my script try the first shebang line, and if it didn't work, to try the second line, as in, 2 first lines in the code would be:

#!/usr/bin/python

#!/usr/bin/python3

Is this possible? Is there a way to support both python and python3 for the script? As in first try the first shebang line, if it didn't work try th second line.

Things I tried to far: I tried changing the shebang line to: #!/usr/bin/env python But it didn't work.

Thanks

like image 371
Johnny S Avatar asked Mar 15 '20 16:03

Johnny S


4 Answers

You could just not have a shebang and execute your script with the appropriate python binary; e.g.

$ python3 yourscript.py

or

$ python yourscript.py

And you don't need executable permission for your script.

So to make it portable, use a wrapper script:

#!/bin/bash

if [ -x /usr/bin/python3 ]; then
  /usr/bin/python3 yourscript.py
else
  /usr/bin/python yourscript.py
fi
like image 80
Duke Leto Avatar answered Oct 20 '22 21:10

Duke Leto


No, you can't. The shebang line is the first line of the script. There can only be one first line.

like image 30
Jörg W Mittag Avatar answered Oct 20 '22 23:10

Jörg W Mittag


While I would suggest always using python3 or a separate wrapper script as detailed in the other answers, it is in fact technically possible to have the Python script serve as its own wrapper script:

#!/bin/sh
"""": 
if type python3 > /dev/null 2>&1
then
    exec python3 "$0" "$@"
elif type python > /dev/null 2>&1
then
    exec python "$0" "$@"
else
    echo >&2 "Python not installed"
fi
exit 1
""" #"

print("Hello World")

When run as a Python script, it'll just run as a regular Python script. When run as a shell script, it'll re-invoke itself with python3 or python.

like image 5
that other guy Avatar answered Oct 20 '22 23:10

that other guy


Conforming to POSIX, the execve(2) system call only has to look at the first line of a script for a #!-line. So using more than one #!-line shouldn't work.

According to PEP-394, on UNIX, python2 should exist when a 2.x version of Python is installed, and python3 should exist when a 3.x version of Python is installed.

It is up to the OS distributor to decide if a python command is present, and if so which version it envokes. So on UNIX, the is no guarantee that python will exist.

So I would suggest the following;

  • If your script supports Python 3, change the shebang line to #!/usr/bin/env python3. If this works on all Linux versions you're using, this is the preferred solution.
  • If that doesn't work, make your script into the console script of a python package with a setup.py. That will ensure a proper shebang-line on installation.

(PEP-394 encourages script distributers to foist the use of virtual environments onto users, which IMO is an unnecessary complication for those that do not need to have different versions of a module installed.)

like image 1
Roland Smith Avatar answered Oct 20 '22 22:10

Roland Smith