Shebang für Shellskripte

Dieser Artikel wurde für die folgenden Ubuntu-Versionen getestet:

Dieser Artikel ist größtenteils für alle Ubuntu-Versionen gültig.

Zum Verständnis dieses Artikels sind folgende Seiten hilfreich:

  1. Einen Editor öffnen

  2. Ein Terminal öffnen

Inhaltsverzeichnis
  1. Komplexität reduzieren
  2. Interpreter
    1. Der Aufruf
    2. Einmal einfach und zurück, und wo war gl...
    3. Was soll das alles - wozu der Wildwuchs?...
      1. Sonstiges
    4. Faustregeln
  3. Links

Wiki/Icons/terminal.png Bei Shellskripten kommt es sporadisch zu Fehlern in Zusammenhang mit dem Shebang und symbolischen Links. Vor allem die Ursache des Fehlers will dieser Artikel erklären.

Das Szenario besteht aus drei Einflussgrößen:

Komplexität reduzieren

Für sich genommen sind die Punkte leicht zu verstehen - alleine, wenn sie sich zu einer Einheit verknüllen, wird die Frage doch ein wenig komplex. Um die Komplexität anzugehen, sollte man die Konzepte isoliert voneinander verstehen - das ist einfach. Danach ist es auch nicht schwer, die Kombination der Effekte zu verstehen.

Interpreter

Ein Skript kann von unterschiedlichen Interpretern interpretiert werden - oder auch nicht. Es gibt einen POSIX-Standard 🇬🇧, den die populären Shells alle ganz gut beherrschen. Was darüber hinausgeht kann die eine Shell aber die andere nicht, und die andere kann jenes, was erstere nicht kann oder anders löst.

Wenn man einen Interpreter ausdrücklich aufruft, dann wird dieser verwendet - ohne wenn und aber; der Shebang schaut in die Röhre, wird also ignoriert. Natürlich kann man nicht erzwingen, dass das Skript in einem Interpreter funktionieren wird, für den es nicht geschrieben wurde. Das Skript wird ja nicht auf magische Weise umgeschrieben.

Der Aufruf

Wenn man den Interpreter explizit aufruft, also beispielsweise

dash script.sh 

dann muss man zuvor das Skript nicht ausführbar machen, weil man den Interpreter ausführt, und das Skript dessen Eingabedatei ist, so wie z.B. ein Bild die Eingabe für ein Grafikprogramm wie Gimp ist.

Lässt man den Interpreter weg, muss man das Skript erst ausführbar machen; dann wird der Shebang ausgewertet, der in der ersten Zeile steht und aus einem Kommentarzeichen # (engl.: sharp) besteht, dem ! (engl.: bang) und dem Pfad zum Interpreter - üblicherweise dem absoluten Pfad, also /bin/bash oder /bin/sh, insgesamt also #!/bin/bash.

script.sh 

Das war ja jetzt alles nicht so schwer - wo ist das Problem?

Zurück zur Komplexität: Jetzt steht im Skript als Shebang #!/bin/sh, aber im Verzeichnis /bin ist sh ein symbolischer Link der auf dash weist, oder in früheren Zeiten auf die bash. Dann kann man doch auch gleich #!/bin/dash schreiben, das ist doch dann gleichbedeutend?

So, das hat die Sache etwas subtiler gemacht, und wer sich davon angeregt fühlt, der schreibt in die eigenen Skripte auch noch Weichen hinein, die unterscheiden, ob das Skript mit vollem Pfad oder relativem Pfad aufgerufen wurde.

Mehr Komplexität gibt es aber hier nicht - das war schon alles.

Was soll das alles - wozu der Wildwuchs?

Es gibt im wesentlichen drei Gründe, sich für die Shell zu interessieren:

Sonstiges

  • Bei Skripten mit Shebang werden vom Linuxkernel die SUID- und SGID-Flags ignoriert.

  • Mittels Shebang kann man ein Skript aufrufen, welches seinerseits wieder einen Shebang hat usw. Allerdings nur vier Rekursionstiefen tief, dann ist Schluss.

  • Der Shebang kann um Parameter erweitert werden:

    #!/bin/bash -f  
  • Skripte in anderen Sprachen wie Lua, Python, Ruby usw. lassen sich analog mit einem Shebang starten - sofern das # dort als Kommentar toleriert wird, also

    #!/usr/bin/python
  • Bei Skripten, bei denen man nicht weiß, auf welcher Unix-Plattform sie landen werden, findet man auch einen zweistufigen Aufruf, weil man beispielsweise nicht weiß, wo Lua installiert ist. Man ruft dann

    #!/usr/bin/env lua 

    auf, und verlässt sich darauf, dass env einheitlich installiert ist, und damit lua im Pfad gefunden wird.

Faustregeln

Soweit nicht anders verordnet, nimmt man

1
#!/bin/bash

als erste Zeile des Skripts.