Unsere bash führt immer nativ für Linux compilierte Kommandos (wie z.B. ls) oder bash-Skripts aus. Mit dem Shebang lassen sich aber beliebige Skriptsprachen wie ein normales Kommando ausführen.

shebang
Der Shebang ist nichts magisches sondern nur eine Anweisung, die in die erste Zeile einer Textdatei gesetzt wird. Sie enthält Informationen darüber, wie die bash mit dem nachfolgenden Text umgehen soll.
Shebang definieren
Nehmen wir mal ein einfaches Hello World Programm in Python.
def main():
print("Hallo von Python!")
if __name__ == "__main__":
main()
Es macht nicht viel außer dem Text Hallo von Python! auf der Console auszugeben. Um es auszuführen, musst du den Pythoninterpreter aufrufen, um den Pythoncode zu übersetzen
python hello.py
Dies ist auf die Dauer lästig. Besser wäre es, den Interpreter automatisch aufrufen zu lassen. Da kommt jetzt der SheBang ins Spiel.
Er wird immer in die allererste Zeile des Codes geschrieben und wird immer mit #!
eingeleitet. Danach folgt das Programm, das die nachfolgende Datei abarbeiten soll. Die bash besitzt keinen eignen Mechanismus, um den Dateityp zu bestimmen und entsprechend zu reagieren.
Machen wir jetzt unser Pythonprogramm zunächst mal ausführbar
chmod u+x hello.py
Jetzt können wir hello.py einfach als Kommando starten.

Die bash versucht den Pythoncode als bash Script zu interpretieren und bricht dann mit Syntaxfehlern ab.
Jetzt ergänzen wir den Shebang als erste Zeile wie folgt: #! /usr/bin/python
#! /usr/bin/python
# Datei: hello.py
def main():
print("Hallo von Python")
if __name__ == "__main__":
main()
Jetzt können wir hello.py ganz normal als Kommando ausführen, da die bash weiß, dass sie den Pythoninterpreter starten muss, um die Datei zu interpretieren.

Andere Interpreter
Der Shebang ist nicht nur auf Python beschränkt, er lässt sich für jede Programmiersprache einsetzen. Im folgenden haben wir das Hello World in Javascript
#! /usr/bin/node
// Datei: hello.js
console.log('Hallo von JavaScript')
Der Shebang definiert bereits Node.js als Interpreter, diesen muss ich allerdings erst noch mit
sudo apt install nodejs -y
auf meinem Raspberry Pi installieren.
Auch hello.js mache ich ausführbar
chmod u+x hello.js
Wenn ich das jetzt mit ./hello.js starte, ruft die bash node auf um das JavaScript zu interpretieren.

Eigener Shebang
Ich wollte mal experimentell sehen, was bei einem Shebang im Hintergrund passiert und habe mir ein kleines Script dazu geschrieben:
#! /usr/bin/bash
# Datei: mybang
echo "0:${0}"
echo "1:${1}"
echo "2:${2}"
Er gibt einfach nur die ersten drei Parameter aus. In hello.py ändere ich den Shebang in #! ./mybang
und rufe das Programm erneut auf. Ich habe bei Tests herausgefunden, dass hier zwingend ein Shebang auf die bash definiert werden muss.

Die ersten drei Parameter sind dann wie folgt gesetzt
:
0
enthält wie üblich den Namen des laufenden Scripts,1
enthält den Namen der zu interpretierenden Datei mit Pfad.- ab 2 sind die Parameter leer.
Was kann man mit diesem Wissen anfangen? Es wäre jetzt möglich, den eigenen Shebang so zu erweitern, dass nur bestimmte User Pythoncode mit Shebang ausführen darf.
#! /usr/bin/bash
# Datei: mybang
echo "0:${0}"
echo "1:${1}"
echo "2:${2}"
if [[ "${USER}" == "pi" ]]; then
echo "User pi darf python ausführen."
python ${1}
else
echo "Du darfst kein Python ausführen."
fi
Genauso könnten wir einen universellen Shebang schreiben, der anhand der Dateiendung entscheidet, welcher Interpreter aufgerufen wird. Aber das machen nur schlechte Programmierer 😉

Zum Schluss noch der Link zum Git-Repository.