Was ist der Unterschied zwischen "Quelle x", ". x ”und“ ./x ”in Bash?

10

Ich habe eine Bash-Quelle run.shwie folgt:

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

Wenn ich es auf zwei Arten ausführe, gibt es unterschiedliche Verhaltensweisen. Der erste Weg ist,

source run.sh

Das Terminal wird nach der Ausführung geschlossen. Der zweite Weg ist,

./run.sh

Dadurch wird das Skript einfach beendet und auf dem Terminal verbleibt. Ich frage, ob es einen Befehl zum Beenden eines Bash-Skripts für beide source run.shund zur ./run.shAusführung gibt. Ich habe es auch versucht return, was unter ./run.shAusführung nicht gut funktioniert .

Im Allgemeinen interessiert mich, warum dies geschieht und was der Unterschied zwischen der Verwendung von "Quelle" und "Quelle" ist. für die Skriptausführung?

Richard
quelle

Antworten:

16

Bevor ich antworte, denke ich, dass einige Klarstellungen erforderlich sind. Lassen Sie uns die folgenden drei Zeilen analysieren:

source run.sh
. run.sh
./run.sh

Die ersten beiden Zeilen sind genau identisch: .ist in der Tat ein Alias ​​für source. Das sourceShell-Skript wird im aktuellen Kontext ausgeführt, daher wird durch einen Aufruf von exitdie Shell beendet.

Die dritte Zeile (die Sie verwirrt) hat jedoch nichts mit den anderen Zeilen zu tun. ./run.shist nur ein Pfad und entspricht (zum Beispiel) /home/user/run.shoder /usr/bin/something. Denken Sie immer daran, dass Befehle in der Shell durch ein Leerzeichen getrennt sind. In diesem Fall lautet der Befehl also nicht ., sondern ./run.sh: Dies bedeutet, dass eine Sub-Shell ausgeführt wird und dass exitdies nur für die Sub-Shell gilt.

Andrea Corbellini
quelle
5

Drei Wege:

Sie können das Skript in eine Funktion einschließen und nur return verwenden.

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

Sie können testen, ob das Skript von einer interaktiven Shell bezogen wird.

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

Sie können versuchen, zurückzukehren, und wenn dies fehlschlägt, beenden Sie das Programm.

return 1 2>/dev/null || exit 1
Geirha
quelle
Irgendwelche Hinweise, wie die magische Beschwörung $- = *i* funktioniert?
deadbeef404
@ deadbeef404 Der spezielle Parameter -enthält die aktuell aktiven Optionsflags. Der Test prüft, ob das -iFlag aktiv ist. Siehe gnu.org/software/bash/manual/html_node/Special-Parameters.html
Geirha
1

Stellen Sie sich den Befehl 'source' wie in der Anweisung 'include' vor. Es nimmt den Inhalt des Arguments und führt es so aus, als ob es direkt ausgeführt würde. In diesem Fall ist Ihr Befehl 'source' mit dem Argument 'run.sh' und run.sh wird genau so ausgeführt, als hätten Sie den Inhalt von run.sh in Ihre Befehlszeile eingegeben.

Wenn Sie './run.sh' ausführen, ist './run.sh' Ihr Befehl und hat keine Argumente. Da diese Datei im Klartext und nicht binär ist, sucht Ihre Shell beim Shebang ('#!' In der ersten Zeile) nach einem Interpreter und findet '/ bin / bash'. Ihre Shell startet dann eine neue Instanz von bash und der Inhalt von run.sh wird in dieser neuen Instanz ausgeführt.

Wenn bash den Befehl 'exit' erreicht, wird es zunächst genau so ausgeführt, als hätten Sie ihn in die Befehlszeile eingegeben. In den zweiten Fällen wird es im Bash-Prozess ausgeführt, den Ihre Shell gestartet hat. Daher erhält nur diese Bash-Instanz den Befehl 'exit'.

Wenn Sie eine Zeile in bash eingeben, wird alles vor dem ersten Leerzeichen als Befehl und alles, was folgt, als Argument behandelt. Der Befehl '.' ist ein Alias ​​von 'source'. Wenn du rennst '. run.sh 'the'. ' ist ein eigenständiger Befehl, da er durch ein Leerzeichen von seinen Argumenten getrennt ist. Wenn Sie './run.sh' ausführen, lautet Ihr Befehl './run.sh' und '.' ist Teil des relativen Pfads zu run.sh mit dem '.' Darstellen Ihres aktuellen Ordners.

raucht2345
quelle
Wenn Sie ein C / C ++ - Programmierer sind, der mit Shell / Bash-Skripten besser werden möchte, ist dies die perfekte Antwort.
Justin