Making shebang work in Debian on the RPi

Shebang”, sometimes called “hashbang”, is a 2 character combination – #! – which looks like a regular comment to several language interepreters (including Python) but tells all versions of Linux to start up a specific interpreter and then use it to “run” the program in that file. The syntax is simple (it does not include the surrounding quote marks or angle brackets): “<#><!><spc><path_to_interpreter>”. Read that “hash exclamation space textual-path-to-the-language-interpreter”.

It just doesn’t look that hard. As it turns out, there are a few pitfalls or potholes in our road to making it work.

Let us assume we have a two line file we want to use as a test of shebang called “sbtest.py”. It looks generally like this:
#! [path-to-3.5-executable]      <—-this is the shebang line
print(“This started Python 3.5!”)      <—-this proves it works
Further assume we want to run it using Python version 3.5. (It goes without saying the Python 3.5 has to be installed on your computer and might be one of several versions you maintain.) Now let us consider some of the potholes we might encounter.

FIRST POTHOLE, “#!<spc>path_to_interpreter” has to be the very first line in the program; no exceptions and this syntax is absolute.

SECOND POTHOLE, the test program has to be located in your current working directory – this assumes you are executing it by just typing the name of the file preceded by the characters “./” – for example “./sbtest.py”. You can see your current working directory with the command “pwd” and then see the files in it with “ls”. If sbtest.py is in your cwd, it has a shot at working.

OR

A slight version of the above: You have to type in the whole absolute path of the program.

Helpful hint: In all of Unix the period (“.”) is a short cut for your current working directory. This is helpful because if your cwd is six levels down (like “home/pi/usr/dir4/dir5/dir6) and your test program is eight levels down, you can avoid typing that part of the path by using “.” as a shortcut. That means if your “sbtest.py” is in “dir8” you can get to it with “./dir7/dir8/sbtest.py” instead of “home/pi/usr/dir4/dir5/dir6/dir7/dir8/sbtest.py”

OR

“sbtest.py” can be found in one of your PATH variables. Think OF PATH as a container in Linux holding the paths that will be searched to find an executable. You can see this list of paths with the command “echo $PATH”. The list of paths, each separated by a semicolon; will be displayed. If your program is not in one of those directories, and you use only it’s name, it will not be found.

THIRD POTHOLE, you have to have the whole correct path to the desired Python interpreter version spelled out in the [path-to-3.5-executable] part of the shebang line. For example something like “/usr/bin/python3.7”. Note in this case the first “/” is an alias or shortcut for the root directory. Also note the location of the version executable may depend on where you installed it.

For some reason I can not explain, I can run my highest installed version of Python with just the command “python” in Debian (Raspian is a version of Debian which is the Pi’s adopted version of Linux which is just Unix by another name – mostly.) This will not work in any variation I try in shebang.

If you don’t know the location of your interpreter, but you can start it from Linux with a command like “python3.7”, you may be able to find its path if you type/execute the following commands in Python immediate mode:
import sys
print(sys.executable)
There is an extended discussion about this to be found at:
https://stackoverflow.com/questions/2589711/find-full-path-of-the-python-interpreter
….this is the way the big boys do it but to me it is easier to use:
import sys
print(“\n”.join(sys.path))
for a nice neat list of paths for your current active version of python.  The operant word is “active”.

You might also find it using the “locate file-name” command but you will get hundreds of lines to sort through and it still might not be there. You may have to install the locate command and use “sudo updatedb” before you do the search.

Last but not least the Python search path is not the same as the Linux search path, which you can see from Linux with:
echo $PATH

I can’t say for sure that these are all the possible pitfalls, but they are the ones I personally fell into while trying to make it work. The combination of these issues makes it seem to me that there is no really guaranteed universal way to make shebang function in a program for every environment. Locally used, it can save an epoch of time as a testing tool.