Was ist der Unterschied zwischen dem Sourcing ('.' Oder 'source') und dem Ausführen einer Datei in Bash?

76

Was ist der Unterschied zwischen dem Ausführen eines Skripts wie folgt:

./test.sh

und Ausführen eines Skripts wie folgt:

. test.sh?

Ich habe ein einfaches zweizeiliges Skript ausprobiert, um festzustellen, ob es einen Unterschied gibt:

#!/bin/bash
ls

Aber beide . test.shund ./test.shdie gleichen Informationen zurückgegeben.

Natan
quelle
Entschuldigung, wenn dies ein Duplikat ist - nach weiteren Untersuchungen habe ich einige Seiten mit relevanten Informationen gefunden, indem ich nach "bash dot" anstelle von "bash" gesucht habe.
Natan
3
Genauso wie test.shes nicht dasselbe ist wie ./test.sh(der erste ruft eine PATHSuche auf), so sind es auch . test.shund . ./test.shauf die gleiche Weise anders (der erste ruft eine Suche auf PATH). Viele Shells scheinen .am Ende PATHeiner .Pfadsuche implizit enthalten zu sein , aber dieses Verhalten ist nicht Standard. Somit ist es genauer, test.shvs . test.shund ./test.shvs zu vergleichen . ./test.sh.
JW013

Antworten:

83

./test.shläuft test.shals separates Programm. Es kann passieren, dass es sich um ein Bash-Skript handelt, wenn die Datei mit test.shbeginnt #!/bin/bash. Es könnte aber auch etwas anderes sein.

. ./test.shFührt den Code der Datei test.shin der laufenden Instanz von bash aus. Es funktioniert so, als ob die Inhaltsdatei test.shanstelle der . ./test.shZeile in Textform eingefügt worden wäre . (Fast: Es gibt einige Details, die sich unterscheiden, z. B. den Wert $BASH_LINENOund das Verhalten des returneingebauten Moduls.)

source ./test.shist identisch mit . ./test.shin bash (in anderen Shells sourcekann es geringfügig anders sein oder gar nicht existieren; .für die Aufnahme in den POSIX-Standard).

Der am häufigsten sichtbare Unterschied zwischen dem Ausführen eines separaten Skripts mit ./test.shund dem Einschließen eines Skripts mit dem .eingebauten Skript besteht darin, dass, wenn das test.shSkript einige Umgebungsvariablen mit einem separaten Prozess festlegt, nur die Umgebung des untergeordneten Prozesses festgelegt wird, während bei Einbeziehung des Skripts die Umgebung des Sole-Shell-Prozesses wird festgelegt. Wenn Sie eine Zeile foo=barin test.shund echo $fooam Ende des aufrufenden Skripts einfügen, sehen Sie den Unterschied:

$ cat test.sh
#!/bin/sh
foo=bar
$ ./test.sh
$ echo $foo

$ . ./test.sh
$ echo $foo
bar
Gilles
quelle
17
Auch das Hinzufügen echo $$zum Skript wird den Unterschied deutlich machen. Die $$Variable enthält die PID der aktuellen Shell.
1
Ein anderes Verwendungsszenario ist die Verwendung des . ./test.shAufrufs aus einem anderen Shell-Skript, um Funktionen zu verwenden, die in test.sh beschrieben werden. Ich meine, Sie können nicht nur Variablen festlegen, sondern auf diese Weise auch neue Funktionen erstellen, die dann über Bash oder ein anderes Skript aufgerufen werden können. . /usr/libexec/company/tools; custom_command "variable"
Rqomey
9

Wenn Sie ein Skript auf die erste Art ausführen, wird es als untergeordneter Prozess ausgeführt. Sourcing hingegen führt das Skript so aus, als ob Sie alle Befehle in die aktuelle Shell eingegeben hätten. Wenn das Skript eine Variable setzt, bleibt diese gesetzt. Wenn das Skript beendet wird, wird Ihre Sitzung beendet. Siehe help .für die Dokumentation.

Choroba
quelle
3

Eine andere Sache, die ich bemerke, ist, dass wenn Sie einen Alias ​​wie diesen haben:

# add into .bashrc_aliases
alias ls='ls -lht'

Mit erhalten ./test.shSie eine normale lsAusgabe (und eine andere PID als die aktuelle Shell):

auraham@pandora:~/iso$ ./test.sh 
dsl-4.4.10.iso  test.sh
3136 # PID

Mit . test.shoder erhalten . ./test.shSie eine detailliertere Ausgabe (und dieselbe PID wie in der aktuellen Shell):

auraham@pandora:~/iso$ echo $$
2767 # shell PID

auraham@pandora:~/iso$ . test.sh 
total 50M
drwxrwxr-x  2 auraham auraham 4.0K Jul 30 15:41 .
-rwxrwxr-x  1 auraham auraham   32 Jul 30 15:41 test.sh
drwxr-xr-x 50 auraham auraham 4.0K Jul 30 15:30 ..
-rw-rw-r--  1 auraham auraham  50M Jul 28 17:24 dsl-4.4.10.iso
2767 # PID
Auraham
quelle
Sie können dies in .bashrc if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi einfügen .bash_aliases. Geben Sie dann Ihre Aliase ein .
Auraham
Natürlich, aber müssen Sie das aliasSchlüsselwort nicht immer noch verwenden ? (Vielleicht ist das nur ein Fehler in Ihrem Beitrag - in Zeile 3?)
Emanuel Berg
Ganz richtig, mein Fehler. Thanks @EmanuelBerg
Auraham
-1

Die Hauptverwendung für mich source(oder .) sind Bash-Funktionen .

Ich habe Skripte mit vielen Funktionen und führe sie alle mit meinem aus .bashrc. Die Funktionen "werden" Befehle, die ich oft benutze.

Willian Paixao
quelle
Ich habe alle drei Methoden in .bashrc ausprobiert - source, die absolute Position des Skripts und der Name des Befehls (Platzieren des Skripts in einem PATH-Ordner) - und alle drei Methoden haben funktioniert.
Emanuel Berg