Wenn die Shell-Skripte mit beginnen #!/bin/bash, werden sie immer mit bashvon ausgeführt /bin. Wenn sie jedoch mit beginnen #!/usr/bin/env bash, suchen sie nach bashin $PATHund beginnen dann mit dem ersten, den sie finden können.
Warum sollte das nützlich sein? Angenommen, Sie möchten bashSkripts ausführen , für die bash 4.x oder höher erforderlich ist, auf Ihrem System jedoch nur bash3.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 ~/binbeispielsweise platzieren. Sie können Ihre $PATHVariable auch so ändern .bash_profile, dass sie ~/binals erster Eintrag enthalten ist ( PATH=$HOME/bin:$PATHda dies ~nicht erweitert wird $PATH). Wenn Sie jetzt anrufen bash, sucht die Shell zuerst in der richtigen $PATHReihenfolge danach, also beginnt sie damit ~/bin, wo sie Ihre findet bash. Dasselbe passiert, wenn Skripte nach bashVerwendung suchen #!/usr/bin/env bash, sodass diese Skripte jetzt mit Ihrem benutzerdefinierten bashBuild 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 envist, 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 envnach einem benannten Interpreter suchen <interpreter> <arg>. Beachten Sie, dass dies kein Problem des envBefehls 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 sudoes nicht für die Bereinigung der Umgebung konfiguriert oder $PATHvon der Bereinigung ausgeschlossen wurde. Lassen Sie mich dies demonstrieren:
In der Regel /binist ein gut geschützter Ort, nur rootkann 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 bashin ein verstecktes Verzeichnis einfügen kann. Ändern Sie Ihr Verzeichnis so, .bash_profiledass dieses Verzeichnis in Ihr Verzeichnis aufgenommen wird $PATH, sodass alle verwendeten Skripte #!/usr/bin/env bashmit dieser Fälschung ausgeführt werden bash. Wenn Sie sudobehalten $PATH, sind Sie in großen Schwierigkeiten.
Angenommen, ein Tool erstellt eine Datei ~/.evil/bashmit 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 sudoaufbewahrt 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. /binWenn 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 /binselbst ein Symlink ist) Ich würde immer mit #!/bin/shund 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/shwürde, es wahrscheinlich immer noch verstehen würde #!/bin/shund 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/binaber sie können auch in sein /usr/local/binoder in einem ganz anderen Hierarchiezweig ( /opt/..., /Applications/..., etc.). Deshalb verwenden diese oft die #!/usr/bin/env xxxShebang-Syntax.