Was ist der bevorzugte Bash Shebang?

1132

Gibt es einen BashShebang, der für die meisten Zwecke objektiv besser ist als die anderen?

  • #!/usr/bin/env bash
  • #!/bin/bash
  • #!/bin/sh
  • #!/bin/sh -
  • usw

Ich erinnere mich vage an eine lange Zeit, als ich hörte, dass das Hinzufügen eines Bindestrichs am Ende verhindert, dass jemand einen Befehl an Ihr Skript übergibt, aber keine Details dazu finden kann.

Kurtosis
quelle
4
Und es ist /usr/local/bin/bashauf OpenBSD.
JWW

Antworten:

1535

Sie sollten #!/usr/bin/env bashfür die Portabilität Folgendes verwenden : Verschiedene * Nixe, die bashan verschiedenen Stellen platziert wurden, und die Verwendung /usr/bin/envist eine Problemumgehung, um die ersten bashauf dem Programm gefundenen Nixe auszuführen PATH. Und shist nichtbash .

l0b0
quelle
9
Vielen Dank. Es sieht auch so aus, als würde das Hinzufügen - am Ende von $! / Usr / bin / env bash - nichts bewirken, da * nix im shebang nur ein Argument zulässt und dieses von 'bash' verwendet wird. Dies ist anscheinend nur nützlich, um zu verhindern, dass böswillige Argumente in der Befehlszeile an das Skript übergeben werden, wenn der Shebang des Skripts einer der anderen ohne Argumente ( /bin/shusw.) ist.
Kurtosis
13
@ Ray bashlebt nicht /binauf allen Systemen.
Ptierno
12
Das gleiche gilt für mich, ich habe es nur einem Alias ​​hinzugefügt: alias shebang='echo "#!/usr/bin/env bash"'Jetzt muss ich nur noch das Terminal öffnen und shebang eingeben, anstatt hierher zu gehen.
Oylex
19
Diese Antwort täuscht. POSIX sagt nicht, dass envdas bei ist /usr/bin/env. Es könnte tatsächlich an /bin/envoder irgendwo sein, solange es sich auf dem Weg befindet. Es könnte sein, /dummy/envwenn in /dummyist PATH. Shebang selbst ist unter POSIX undefiniert, daher könnte ich #!stop toasterdie USB-Kaffeemaschine starten und POSIX-konform sein. Ist #!/usr/bin/env bashalso nicht besonders besser als #!/bin/bash, es könnte je nach tragbarer sein.
Darkfeline
19
@darkfeline Portabilität ist nicht absolut - es ist mathematisch unmöglich, ein Skript zu erstellen, das auf jeder Plattform dasselbe tut. Von 2012 bis 2018 /usr/bin/envgibt es auf mehr Computern als auf /bin/bashxor /usr/bin/bash, sodass ein Skript, das mit dieser Zeile beginnt , auf so vielen Computern wie möglich die erwartete Leistung erbringt.
10.
80

/bin/shist in der Regel eine Verknüpfung zur Standard-Shell des Systems, die häufig bashaber auf zB Debian-Systemen das geringere Gewicht aufweist dash. In jedem Fall ist die ursprüngliche Bourne-Shell. shWenn Ihr Skript also einige bash(2. Generation, "Bourne Again sh") spezifische Funktionen ( [[ ]]Tests, Arrays, verschiedene zuckerhaltige Dinge usw.) verwendet, sollten Sie spezifischer sein und die späteren verwenden . Auf diese Weise wird Ihr Skript auf Systemen, auf denen bash nicht installiert ist, nicht ausgeführt. Ich verstehe, dass es vielleicht eine aufregende Trilogie von Filmen über diese Entwicklung gibt ... aber das könnte Hörensagen sein.

Beachten Sie auch , dass , wenn evoziert wie sh, bashin gewissem Maße verhält sich wie POSIX - Standard sh (siehe auch die GNU - Dokumentation über diese).

empfindliches Gitterfieber
quelle
2
Die Public Domain Korn Shell (pdksh) ist unter OpenBSD Standard.
JWW
Die meisten Systeme stellen keine Verbindung /bin/shzu einer beliebigen Stelle her, /usrda dies die Ausführung der Init-Skripte vor dem Mounten erschweren würde /usr.
aij
@aij Ich weiß nicht, warum ich "viele oder die meisten" dort abgelegt habe - ich bin ein Fedora-Benutzer, bei dem /binund /sbinseit Jahren standardmäßig nur Symlinks zu /usr/binund vorhanden /usr/sbinsind. In diesem Zusammenhang /bin/shhandelt es sich also um einen Link zu bashund den tatsächlichen Verzeichnis ist /usr/bin. Aber ich werde das oben korrigieren.
empfindliches
44

Ich empfehle:

#!/bin/bash

Es ist nicht 100% portabel (einige Systeme befinden sich bashan einem anderen Ort als /bin), aber die Tatsache, dass viele vorhandene Skripte #!/bin/bashDruck auf verschiedene Betriebssysteme ausüben, um /bin/bashzumindest eine Symlink-Verbindung zum Hauptstandort herzustellen .

Die Alternative von:

#!/usr/bin/env bash

wurde vorgeschlagen - aber es gibt keine Garantie dafür, dass der envBefehl vorhanden ist /usr/bin(und ich habe Systeme verwendet, bei denen dies nicht der Fall ist). Darüber hinaus wird in diesem Formular die erste Instanz von bashin den aktuellen Benutzern verwendet $PATH, die möglicherweise keine geeignete Version der Bash-Shell ist.

(Sollte aber /usr/bin/envauf jedem einigermaßen modernen System funktionieren, entweder weil enves installiert ist /usr/binoder weil das System etwas tut, damit es funktioniert. Das System, auf das ich oben Bezug genommen habe, war SunOS 4, das ich wahrscheinlich seit etwa 25 Jahren nicht mehr verwendet habe.)

Wenn Sie ein Skript benötigen, um auf einem System ausgeführt zu werden, das nicht vorhanden ist /bin/bash, können Sie das Skript so ändern , dass es auf den richtigen Speicherort verweist (was zugegebenermaßen unpraktisch ist).

Ich habe die Kompromisse in meiner Antwort auf diese Frage ausführlicher erörtert .

Ein etwas obskures Update: Ein System, das ich verwende, Termux , eine Desktop-Linux-ähnliche Schicht, die unter Android ausgeführt wird, hat /bin/bash( bashist /data/data/com.termux/files/usr/bin/bash) nicht - aber es muss speziell behandelt werden #!/bin/bash.

Keith Thompson
quelle
3
2 Jahre später und dies ist immer noch der beste Rat hier. Wenn die einfache Lösung nicht funktioniert, müssen Sie Ihre früheren Entscheidungen in Frage stellen. Die akzeptierte und am besten bewertete Antwort ist nicht falsch, sie ist einfach nicht richtig :)
Software Engineer
27

Die Verwendung einer Shebang-Zeile zum Aufrufen des entsprechenden Interpreters ist nicht nur für BASH gedacht. Sie können den Shebang für jede interpretierte Sprache auf Ihrem System verwenden, z. B. Perl, Python, PHP (CLI) und viele andere. Übrigens der Schebang

#!/bin/sh -

(Es können auch zwei Striche sein, dh --) Beendet Bash-Optionen. Alles, was danach folgt, wird als Dateiname und Argument behandelt.

Wenn Sie den envBefehl verwenden, wird Ihr Skript portabel und Sie können benutzerdefinierte Umgebungen für Ihr Skript einrichten. Daher sollten tragbare Skripte verwendet werden

#!/usr/bin/env bash

Oder für welche Sprache auch immer wie für Perl

#!/usr/bin/env perl

Schauen Sie sich unbedingt die manSeiten an für bash:

man bash

und env:

man env

Hinweis: Auf Debian und Debian-basierten Systemen wie Ubuntu shist dashnicht verbunden bash. Wie alle Systemskripte verwenden sh. Dies ermöglicht laut Debian, dass Bash wächst und das System stabil bleibt.

Um den Aufruf * nix beizubehalten, verwende ich niemals Dateierweiterungen für von Shebang aufgerufene Skripte, da Sie die Erweiterung beim Aufruf für ausführbare Dateien nicht wie unter Windows weglassen können. Der Dateibefehl kann es als Skript identifizieren.

Jamie R Robillard Sr.
quelle
4

Es hängt wirklich davon ab, wie Sie Ihre Bash-Skripte schreiben. Wenn Ihr /bin/shSymbol mit Bash verknüpft ist und Bash als aufgerufen wird sh, sind einige Funktionen nicht verfügbar .

Wenn Sie bash-spezifische Nicht-POSIX-Funktionen wünschen, verwenden Sie #!/bin/bash

Glenn Jackman
quelle
3
Bash ist unter OpenBSD nicht installiert. Wenn Sie es über installieren, befindet es pkg_addsich in /usr/local/bin, das möglicherweise nicht auf dem Pfad ist.
JWW
Wie wäre es mit einer POSIXFunktion?
Nikolan Asad