Was ist der Unterschied zwischen dem Ausführen von "bash script.sh" und "./script.sh"?

42

Wenn script.sh nur so etwas wie typisch ist

#!/bin/bash
echo "Hello World!"

Gibt es eine bevorzugte Methode zum Ausführen des Skripts? Ich denke, Sie müssen es zuerst ändern, damit es ausführbar wird?

user72136
quelle

Antworten:

56

Für Ihr spezifisches Skript funktioniert jeder Weg, außer dass ./script.shdie Ausführung und lesbare Bits bash script.sherforderlich sind , während nur lesbare Bits erforderlich sind.


Der Grund für den Unterschied in der Berechtigungsanforderung liegt darin, wie das Programm geladen wird, das Ihr Skript interpretiert:

  • ./script.sh Lässt Ihre Shell die Datei so ausführen, als ob sie eine reguläre ausführbare Datei wäre.

Die Shell teilt sich selbst mit und verwendet einen Systemaufruf (z. B. execve), damit das Betriebssystem die Datei im gegabelten Prozess ausführt. Das Betriebssystem überprüft die Dateiberechtigungen (daher muss das Ausführungsbit gesetzt sein) und leitet die Anforderung an den Programmlader weiter , der die Datei ansieht und festlegt, wie sie ausgeführt werden soll. Unter Linux beginnen kompilierte ausführbare Dateien mit einer magischen ELF- Nummer, während Skripte mit einem #!( Hash ) beginnen. Ein Hashbang-Header bedeutet, dass die Datei ein Skript ist und von dem Programm interpretiert werden muss, das nach dem Hashbang angegeben ist. Dadurch kann ein Skript selbst dem System mitteilen, wie es das Skript interpretiert.

Mit Ihrem Skript wird der Programmlader ausgeführt /bin/bashund ./script.sh als Befehlszeilenargument übergeben.

  • bash script.shLässt Ihre Shell als Befehlszeilenargument laufen bashund übergebenscript.sh

Das Betriebssystem wird also geladen bash(wird nicht einmal angezeigt script.sh, da es sich nur um ein Befehlszeilenargument handelt). Der erstellte bashProzess interpretiert dann das, script.shweil es als Befehlszeilenargument übergeben wird. Da script.shnur bashals reguläre Datei gelesen wird , ist das Ausführungsbit nicht erforderlich.


Ich empfehle jedoch die Verwendung ./script.sh, da Sie möglicherweise nicht wissen, welchen Interpreter das Skript benötigt. Lassen Sie den Programmlader das für Sie bestimmen.

SkyDan
quelle
3
Wenn das ausführbare Bit nicht gesetzt ist, können Sie das Skript auch ausführen, indem Sie "./script.sh"
Hund frisst Katzenwelt
1
@Hund Du bist richtig. Der Punkt ist eine Abkürzung für den eingebauten Befehl 'source', der das Skript im aktuellen Bash-Prozess ausführt. Es wird also nur das lesbare Bit benötigt.
SkyDan
5
@ Dogeatcatworld während das wahr ist, läuft . ./script.shnicht das Gleiche wie bash script.sh(oder ./script.sh. Betrachten Sie das Skript #!/usr/bin/python -V<newline> print test.
Casey
12
Beachten Sie, dass die Beschaffung eines Skripts zu einer Kontamination der interaktiven Sitzung führen kann. Sollte beispielsweise ein Skript die Umgebungsvariable PATH ändern, wirkt sich diese Änderung auf Befehle aus, die nach der Quelle ausgeführt werden. Dieser Ansatz sollte wirklich für Situationen reserviert werden, in denen Sie von den Nebenwirkungen abhängen (Umgebungs-Setup-Skripts und dergleichen). In anderen Situationen, in denen Sie die Berechtigungen nicht ändern können, ist es am sichersten, den Befehl in der shebang-Zeile gefolgt vom Skriptnamen auszuführen.
ctt
6
Beachten Sie, dass Sie ./ nicht verwenden müssen, wenn Sie ein Skript im aktuellen Verzeichnis erstellen . sag einfach . script.sh. Aber ich stimme den Leuten zu, die davon abraten, den .Befehl für Skripte zu verwenden, die nicht auf diese Weise aufgerufen werden sollten. Ich bin überrascht, dass niemand erwähnt hat, dass das Skript, wenn es exitBefehle enthält und Sie es als Quelle verwenden, Sie abmelden könnte. Ein weniger ernstes Problem wäre, wenn das Skript eine ausführt cd, da dies auch die übergeordnete (interaktive) Shell betreffen würde.
Scott
18

bash script.shRuft das Skript direkt mit der Bash auf.
./script.shverwendet den shebang #!/bin/bash, um zu bestimmen, wie ausgeführt werden soll.

Wenn Sie wirklich wissen möchten, welche Binärdatei ausgeführt wird, wenn Sie eine bash script.shausführen, können Sie mit herausfinden which bash.

In Ihrem Beispiel macht das also keinen Unterschied. Ja, Sie müssen chmod +x script.shes direkt über ausführen können ./script.sh.

xx4h
quelle
2
Nun, es macht keinen Unterschied, vorausgesetzt, das /bin/bashist das erste bashin deinem $PATH.
cjm
Du hast recht. Und der Shebang #!/bin/bashfunktioniert nur, wenn es einen/bin/bash
xx4h
Bash (Version 4.2.37) auf meinem System führt Skripte auch ohne gesetztes Ausführungsbit aus. Warum ist ein Ausführungsbit erforderlich?
SkyDan
Ja, das Ausführungsbit wird nur beim Aufrufen von via benötigt ./script.sh.
xx4h
4

Erstellen Sie eine Datei Delete_Self.sh wie folgt:

 #!/bin/rm

 echo I am still here!

Führen Sie dieses Skript aus, wie sh Delete_Self.shSie sehen werden "Ich bin immer noch hier!" hallte zurück.

Machen Sie es ausführbar und führen Sie es so ./Delete_Self.shaus, wie Sie sehen, dass nichts zurückgesendet wird, während die Datei Delete_Self.shselbst weg ist.

Der Unterschied ist also, dass:

  • bash script.shignoriert das #! line, da bash als Programm zum Ausführen von script.sh angegeben ist.
  • ./script.shwird das # lesen! Zeile, um das auszuführende Programm zu bestimmen script.sh.
David
quelle
+1 für das nette Beispiel
ThisaruG
1

Zusätzlich zu den anderen Antworten ist es nützlich , den Unterschied zwischen dem Ausführen eines Skripts über ./script.sh(i) und dem Ausführen von Quelle ./script.sh(ii) zu kennen. - Die Version (i) erstellt eine neue Shell, in der der Befehl ausgeführt werden kann, während (ii) sie in der ausführt Aktuelle Shell - Dies kann obligatorisch sein, wenn die ausführbare Datei Umgebungsvariablen ändert, die nach dem Beenden der ausführbaren Datei beibehalten werden müssen. Um beispielsweise eine Python-Conda-Umgebung zu aktivieren, muss Folgendes verwendet werden:

source activate my_env

NB Eine andere Alternative, auf sourcedie Sie möglicherweise stoßen, ist das .eingebaute, dh

. activate my_env
einonm
quelle