Wenn die Shell-Skripte mit beginnen #!/bin/bash
, werden sie immer mit bash
von ausgeführt /bin
. Wenn sie jedoch mit beginnen #!/usr/bin/env bash
, suchen sie nach bash
in $PATH
und beginnen dann mit dem ersten, den sie finden können.
Warum sollte das nützlich sein? Angenommen, Sie möchten bash
Skripts ausführen , für die bash 4.x oder höher erforderlich ist, auf Ihrem System jedoch nur bash
3.x installiert ist und Ihre Distribution derzeit keine neuere Version anbietet oder Sie kein Administrator sind und nicht ändern können, was auf diesem System installiert ist .
Natürlich können Sie Bash-Quellcode herunterladen und Ihre eigene Bash von Grund auf neu erstellen, indem Sie sie ~/bin
beispielsweise platzieren. Sie können Ihre $PATH
Variable auch so ändern .bash_profile
, dass sie ~/bin
als erster Eintrag enthalten ist ( PATH=$HOME/bin:$PATH
da dies ~
nicht erweitert wird $PATH
). Wenn Sie jetzt anrufen bash
, sucht die Shell zuerst in der richtigen $PATH
Reihenfolge danach, also beginnt sie damit ~/bin
, wo sie Ihre findet bash
. Dasselbe passiert, wenn Skripte nach bash
Verwendung suchen #!/usr/bin/env bash
, sodass diese Skripte jetzt mit Ihrem benutzerdefinierten bash
Build auf Ihrem System funktionieren .
Ein Nachteil ist, dass dies zu unerwartetem Verhalten führen kann, z. B. dass dasselbe Skript auf demselben Computer mit unterschiedlichen Interpreten für unterschiedliche Umgebungen oder Benutzer mit unterschiedlichen Suchpfaden ausgeführt wird, was zu Kopfschmerzen aller Art führt.
Der größte Nachteil dabei env
ist, dass einige Systeme nur ein Argument zulassen, sodass Sie dies nicht tun können #!/usr/bin/env <interpreter> <arg>
, da die Systeme <interpreter> <arg>
als ein Argument sehen (sie behandeln es so, als ob der Ausdruck in Anführungszeichen gesetzt wäre) und daher env
nach einem benannten Interpreter suchen <interpreter> <arg>
. Beachten Sie, dass dies kein Problem des env
Befehls selbst ist, bei dem immer mehrere Parameter übergeben werden konnten, sondern mit dem Shebang-Parser des Systems, das diese Zeile vor dem Aufruf analysiert env
. In der Zwischenzeit wurde dies auf den meisten Systemen behoben. Wenn Ihr Skript jedoch extrem portabel sein soll, können Sie sich nicht darauf verlassen, dass dies auf dem System behoben wurde, das Sie ausführen werden.
Dies kann sogar Auswirkungen auf die Sicherheit haben, z. B. wenn sudo
es nicht für die Bereinigung der Umgebung konfiguriert oder $PATH
von der Bereinigung ausgeschlossen wurde. Lassen Sie mich dies demonstrieren:
In der Regel /bin
ist ein gut geschützter Ort, nur root
kann dort etwas ändern. Ihr Home-Verzeichnis ist jedoch kein Programm, das Sie ausführen, um Änderungen daran vorzunehmen. Das bedeutet, dass bösartiger Code eine Fälschung bash
in ein verstecktes Verzeichnis einfügen kann. Ändern Sie Ihr Verzeichnis so, .bash_profile
dass dieses Verzeichnis in Ihr Verzeichnis aufgenommen wird $PATH
, sodass alle verwendeten Skripte #!/usr/bin/env bash
mit dieser Fälschung ausgeführt werden bash
. Wenn Sie sudo
behalten $PATH
, sind Sie in großen Schwierigkeiten.
Angenommen, ein Tool erstellt eine Datei ~/.evil/bash
mit folgendem Inhalt:
#!/bin/bash
if [ $EUID -eq 0 ]; then
echo "All your base are belong to us..."
# We are root - do whatever you want to do
fi
/bin/bash "$@"
Lassen Sie uns ein einfaches Skript erstellen sample.sh
:
#!/usr/bin/env bash
echo "Hello World"
Proof of Concept (auf einem System, auf dem sudo
aufbewahrt wird $PATH
):
$ ./sample.sh
Hello World
$ sudo ./sample.sh
Hello World
$ export PATH="$HOME/.evil:$PATH"
$ ./sample.sh
Hello World
$ sudo ./sample.sh
All your base are belong to us...
Hello World
Normalerweise sollten sich die klassischen Shells alle in befinden. /bin
Wenn Sie sie aus irgendeinem Grund nicht dort platzieren möchten, ist es wirklich kein Problem, einen Symlink zu platzieren /bin
, der auf ihre tatsächlichen Positionen verweist (oder vielleicht /bin
selbst ein Symlink ist) Ich würde immer mit #!/bin/sh
und gehen #!/bin/bash
. Es gibt einfach zu viel, was kaputt gehen würde, wenn diese nicht mehr funktionieren würden. Es ist nicht so, dass POSIX diese Position benötigen würde (POSIX standardisiert keine Pfadnamen und damit überhaupt nicht die Shebang-Funktion), aber sie sind so häufig, dass selbst wenn ein System keine anbieten /bin/sh
würde, es wahrscheinlich immer noch verstehen würde #!/bin/sh
und wissen, was damit zu tun ist und möglicherweise nur aus Gründen der Kompatibilität mit vorhandenem Code.
Für modernere, nicht standardmäßige, optionale Interpreter wie Perl, PHP, Python oder Ruby wird jedoch nicht genau angegeben, wo sie sich befinden sollen. Sie werden in können /usr/bin
aber sie können auch in sein /usr/local/bin
oder in einem ganz anderen Hierarchiezweig ( /opt/...
, /Applications/...
, etc.). Deshalb verwenden diese oft die #!/usr/bin/env xxx
Shebang-Syntax.