it-swarm.com.de

Was ist der Unterschied zwischen "#! / Usr / bin / env bash" und "#! / Usr / bin / bash"?

Was ist der Unterschied zwischen diesen beiden Anweisungen in der Kopfzeile eines Skripts bash?

  1. #!/usr/bin/env bash

  2. #!/usr/bin/bash

Als ich versuchte, die Manpage env zu sehen, erhalte ich diese Definition:

 env - run a program in a modified environment

Was heißt das?

304
tarrsalah

Das Ausführen eines Befehls über /usr/bin/env Hat den Vorteil, nach der Standardversion des Programms zu suchen, die sich in Ihrer aktuellen env ironment befindet.

Auf diese Weise müssen Sie nicht an einer bestimmten Stelle im System danach suchen, da sich diese Pfade möglicherweise an verschiedenen Orten auf verschiedenen Systemen befinden. Solange es auf deinem Weg ist, wird es es finden.

Ein Nachteil ist, dass Sie nicht mehr als ein Argument übergeben können (zB können Sie nicht /usr/bin/env awk -f Schreiben), wenn Sie Linux unterstützen möchten, wie POSIX ist vage wie das line ist zu interpretieren, und Linux interpretiert alles nach dem ersten Leerzeichen, um ein einzelnes Argument zu bezeichnen. Sie können /usr/bin/env -S Für einige Versionen von env verwenden, um dies zu umgehen, aber dann wird das Skript noch weniger portabel und bricht auf relativ neuen Systemen (z. B. sogar Ubuntu 16.04, wenn nicht später).

Ein weiterer Nachteil besteht darin, dass Sie keine explizite ausführbare Datei aufrufen, was zu Fehlern und Sicherheitsproblemen auf Mehrbenutzersystemen führen kann (wenn es jemandem gelungen ist, die ausführbare Datei mit dem Namen bash in Ihren Pfad aufzunehmen).

#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash     #gives you explicit control on a given system of what executable is called

In einigen Situationen kann die erste bevorzugt sein (wie das Ausführen von python Skripten mit mehreren Python-Versionen, ohne dass die ausführbare Zeile überarbeitet werden muss) bevorzugt werden, da dies die Code-Injection-Möglichkeiten einschränkt.

276
Alec Bennett

Mit #!/usr/bin/env NAME veranlasst die Shell, nach der ersten Übereinstimmung von NAME in der Umgebungsvariablen $ PATH zu suchen. Dies kann hilfreich sein, wenn Sie den absoluten Pfad nicht kennen oder nicht danach suchen möchten.

50
Dolphiniac

Anstatt den Pfad zum Interpreter explizit wie in /usr/bin/bash/ Mit dem Befehl env wird der Interpreter gesucht und dort gestartet, wo er zuerst gefunden wurde. Dies hat beide Vor- und Nachteile

11
safay

Wenn die Shell-Skripte mit #!/bin/bash Beginnen, werden sie immer mit bash von /bin Ausgeführt. Wenn sie jedoch mit #!/usr/bin/env bash Beginnen, suchen sie in $PATH Nach bash und beginnen dann mit dem ersten, den sie finden können.

Warum wäre das nützlich? Angenommen, Sie möchten bash Skripte ausführen, für die Bash 4.x oder höher erforderlich ist. Auf Ihrem System ist jedoch nur bash 3.x installiert, und zurzeit bietet Ihre Distribution keine neuere Version an sind keine Administratoren und können nicht ändern, was auf diesem System installiert ist.

Natürlich können Sie Bash-Quellcode herunterladen und Ihren eigenen Bash von Grund auf neu erstellen, indem Sie ihn beispielsweise auf ~/bin Platzieren. Sie können auch die Variable $PATH In Ihrer .bash_profile - Datei so ändern, dass sie ~/bin Als ersten Eintrag enthält (PATH=$HOME/bin:$PATH, Da ~ Dies nicht tut erweitern in $PATH). Wenn Sie jetzt bash aufrufen, sucht die Shell zuerst in der Reihenfolge $PATH Danach. Sie beginnt also mit ~/bin, Wo sie Ihr bash findet. . Dasselbe passiert, wenn Skripte mit #!/usr/bin/env bash Nach bash suchen, 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. Dasselbe Skript auf demselben Computer wird möglicherweise mit unterschiedlichen Interpreten für unterschiedliche Umgebungen oder Benutzer mit unterschiedlichen Suchpfaden ausgeführt, was zu Kopfschmerzen aller Art führt.

Der größte Nachteil von env ist, dass einige Systeme nur ein Argument zulassen. Sie können dies also nicht tun #!/usr/bin/env <interpreter> <arg>, Da die Systeme <interpreter> <arg> Als ein Argument sehen (sie werden es behandeln) Es ist, als ob der Ausdruck in Anführungszeichen gesetzt wäre. Daher sucht env nach einem Interpreter mit dem Namen <interpreter> <arg>. Beachten Sie, dass dies kein Problem des Befehls env selbst ist, mit dem immer mehrere Parameter übergeben werden konnten, jedoch mit dem Shebang-Parser des Systems, das diese Zeile analysiert, bevor env aufgerufen wird. 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 von Ihnen ausgeführten System behoben wurde.

Es kann sogar Auswirkungen auf die Sicherheit haben, z. wenn Sudo nicht für die Bereinigung der Umgebung konfiguriert wurde oder $PATH von der Bereinigung ausgeschlossen wurde. Lassen Sie mich das demonstrieren:

Normalerweise ist /bin Ein gut geschützter Ort, nur root kann dort etwas ändern. Ihr Home-Verzeichnis kann jedoch von keinem Ihrer Programme geändert werden. Das bedeutet, dass böswilliger Code ein falsches bash in ein verstecktes Verzeichnis legen könnte. Ändern Sie Ihren .bash_profile, Um dieses Verzeichnis in Ihren $PATH Aufzunehmen, sodass alle Skripte #!/usr/bin/env bash Verwenden. wird am Ende mit diesem gefälschten bash ausgeführt. Wenn Sudo$PATH Behält, sind Sie in großen Schwierigkeiten.

Z.B. Stellen Sie sich vor, 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 "[email protected]"

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$PATH Aufbewahrt):

$ ./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 /bin Befinden, und wenn Sie sie aus irgendeinem Grund nicht dort platzieren möchten, ist es wirklich kein Problem, einen Symlink in /bin Zu platzieren, der auf sie verweist reale Orte (oder vielleicht /bin selbst ist ein Symlink), also würde ich immer mit #!/bin/sh und #!/bin/bash gehen. Es würde einfach zu viel kaputt gehen, wenn diese nicht mehr funktionieren würden. Es ist nicht so, dass POSIX diese Position benötigt (POSIX standardisiert keine Pfadnamen und standardisiert daher nicht einmal die Shebang-Funktion), aber sie sind so verbreitet, dass selbst wenn ein System keinen /bin/sh Es würde wahrscheinlich immer noch #!/bin/sh verstehen und wissen, was damit zu tun ist.

Für modernere, nicht standardmäßige, optionale Interpreter wie Perl, PHP, Python oder Ruby ist dies jedoch nirgends angegeben, wo sie sich befinden sollten. Sie können sich in /usr/bin, Aber auch in /usr/local/bin Oder in einem völlig anderen Hierarchiezweig (/opt/..., /Applications/... Usw.) befinden. Deshalb verwenden diese häufig die Shebang-Syntax #!/usr/bin/env xxx.

3
Mecki

Ich finde es nützlich, weil ich, als ich nicht über env Bescheid wusste, bevor ich anfing, ein Skript zu schreiben, Folgendes tat:

type nodejs > scriptname.js #or any other environment

und dann habe ich diese Zeile in der Datei in Shebang geändert.
Ich habe das gemacht, weil ich mich nicht immer daran erinnerte, wo sich Nodejs auf meinem Computer befinden -/usr/bin/oder/bin /, also ist env für mich sehr nützlich. Vielleicht gibt es Details dazu, aber das ist mein Grund

3
sudo97