Jede Möglichkeit, das Bash-Skript zu beenden, aber das Terminal nicht zu verlassen

182

Wenn ich einen exitBefehl in einem Shell-Skript verwende, beendet das Skript das Terminal (die Eingabeaufforderung). Gibt es eine Möglichkeit, ein Skript zu beenden und dann im Terminal zu bleiben?

Es run.shwird erwartet, dass mein Skript ausgeführt wird, indem es direkt oder von einem anderen Skript bezogen wird.

EDIT: Genauer gesagt gibt es zwei Skripte run2.shals

...
. run.sh
echo "place A"
...

und run.shals

...
exit
...

Wenn ich es vorbeifahre . run2.shund wenn es die exitCodeline erreicht run.sh, möchte ich, dass es am Terminal anhält und dort bleibt. Bei Verwendung exitwird jedoch das gesamte Terminal geschlossen.

PS: Ich habe versucht zu verwenden return, aber echoCodeline wird immer noch ausgeführt ...

Richard
quelle
5
Ich muss wirklich, wirklich, wirklich fragen: Warum verwenden Sie exit in einem Sourcing-Skript?
Ignacio Vazquez-Abrams
3
Der Befehl exit sollte Ihre Terminalsitzung / Anmeldung nicht beenden. Wenn Sie exit 0das Skript nach Erfolg beenden, wenn Sie Ihr Skript ausführen, z. B.: ./test.shSie sollten die Ausgabe sehen, aber Ihre Konsole bleibt geöffnet.
Ben Ashton
Sie könnten den shellBefehl verwenden, der tatsächlich ein Shell-Terminal öffnet. Meine eigene Erfahrung ist jedoch, dass dies nicht mit passiert exit. Beim Beenden wird das Steuerelement normalerweise an das übergeordnete Skript zurückgegeben.
Willem Van Onsem

Antworten:

258

Das "Problem" ist wirklich, dass Sie das Skript beschaffen und nicht ausführen. Wenn Sie eine Datei als Quelle verwenden, wird deren Inhalt in der aktuellen Shell ausgeführt, anstatt eine Subshell zu erzeugen. Alles, einschließlich Exit, wirkt sich also auf die aktuelle Shell aus.

Anstatt zu verwenden exit, möchten Sie verwenden return.

Dominik Honnef
quelle
2
Hier ist eine weitere Erklärung, die ich hilfreich fand: askubuntu.com/a/53179/148337
3cheesewheel
Obwohl richtig, ist dies keine gute Antwort. Es wird ignoriert, dass das aufrufende Skript möglicherweise Variablen oder Funktionen deklariert, auf die das aufgerufene Skript Zugriff benötigt. Besser zu erklären, wie ein Rückkehrcode festgelegt und dann in runs.sh@ruakh verarbeitet wird, hat die bessere Antwort auf diese Frage.
MikeSchinkel
5
Was ist, wenn die Funktion ein verschachtelter Aufruf ist? dh a ruft b an, b ruft c an, c möchte a und b sofort verlassen.
Michael
Die Quelle ist fast die gleiche wie beim Kopieren und Einfügen. Es ist besser zu verwenden sh <script>oder bash <script>wenn man ein Skript ausführen und irgendwann beenden möchte
Peterchaula
42

Ja; Sie können returnanstelle von verwenden exit. Sein Hauptzweck ist die Rückkehr von einer Shell-Funktion, aber wenn Sie sie innerhalb von a verwendensource -d-Skript verwenden, wird sie von diesem Skript zurückgegeben.

In §4.1 "Bourne Shell Builtins" des Bash-Referenzhandbuchs heißt es:

     return [n]

Eine Shell-Funktion wird mit dem Rückgabewert n beendet . Wenn n nicht angegeben wird, ist der Rückgabewert der Exit-Status des zuletzt in der Funktion ausgeführten Befehls. Dies kann auch verwendet werden, um die Ausführung eines Skripts zu beenden, das mit dem eingebauten .(oder source) ausgeführt wird, wobei entweder n oder der Beendigungsstatus des letzten im Skript ausgeführten Befehls als Beendigungsstatus des Skripts zurückgegeben wird . Jeder dem RETURNTrap zugeordnete Befehl wird ausgeführt, bevor die Ausführung nach der Funktion oder dem Skript fortgesetzt wird. Der Rückgabestatus ist ungleich Null, wenn returner außerhalb einer Funktion und nicht während der Ausführung eines Skripts durch .oder verwendet wird source.

Ruakh
quelle
3
returnkann NUR von einer Funktion verwendet werden. Wenn Sie returnes als Shell-Skript verwenden und ausführen (z. B. sh run.sh), meldet bash einen Fehler - return: can only Rückgabe 'von einer Funktion oder einem Sourcing-Skript'
Tzunghsing David Wong
@TzungsingDavidWong: Ist Ihnen klar, dass der Großteil dieser Antwort ein Zitat aus dem offiziellen Referenzhandbuch ist? Und dass die von Ihnen zitierte Fehlermeldung mit dieser Antwort übereinstimmt und nicht mit Ihrer Behauptung?
Ruakh
Ich bin nicht anderer Meinung als Sie. Ich möchte nur darauf hinweisen, dass dies returnnicht funktioniert, wenn das Skript als Shell-Skript ausgeführt und nicht von ausgeführt wird. (oder source). Übrigens, wo finde ich das Dokument source -d?
Tzunghsing David Wong
9

Anstatt das Skript mit . run2.shauszuführen, können Sie es auch mit sh run2.shoder ausführenbash run2.sh

Eine neue Sub-Shell wird gestartet. Um das Skript auszuführen, wird sie am Ende des Skripts geschlossen, wobei die andere Shell geöffnet bleibt.

Viorel Mirea
quelle
Wenn ja, warum dann der zweite Parameter sh "." run2.sh?
CHAN
@ H0WARD Du hast recht, ich habe vergessen, die Punkte zu entfernen. Ich habe die Antwort jetzt bearbeitet.
Viorel Mirea
1
Das OP gibt die Quelle explizit als Anforderung an.
Jonathan Neufeld
3

Sie können nach der return-Anweisung / dem Befehl einen zusätzlichen Exit-Befehl hinzufügen, damit er für beide funktioniert, indem das Skript über die Befehlszeile ausgeführt und über das Terminal bezogen wird.

Beispiel für einen Exit-Code im Skript:

   if [ $# -lt 2 ]; then
     echo "Needs at least two arguments"
     return 1 2>/dev/null
     exit 1
   fi

Die Zeile mit dem exitBefehl wird nicht aufgerufen, wenn Sie das Skript nach demreturn Befehl .

Wenn Sie das Skript ausführen, returngibt der Befehl einen Fehler aus. Daher unterdrücken wir die Fehlermeldung, indem wir sie an weiterleiten /dev/null.

kein Name
quelle
3

Eigentlich denke ich, dass Sie verwirrt sein könnten, wie Sie shoult run a script .

Wenn Sie beispielsweise shein Skript ausführen sh ./run2.sh, auch wenn das eingebettete Skript mit endetexit bleibt Ihr Terminalfenster .

Wenn Sie jedoch .oder verwendensource , wird Ihr Terminalfenster auch beendet / geschlossen, wenn der Index endet.

Weitere Informationen finden Sie unter Was ist der Unterschied zwischen shund source?

karl li
quelle
2

Dies ist genau so, als würden Sie eine Ausführungsfunktion in Ihr Skript run2.sh einfügen. Sie verwenden den Exit-Code in run, während Sie Ihre run2.sh-Datei in der bash tty als Quelle verwenden. Wenn die Funktion "run" ausgeführt wird, um das Skript zu beenden, und "run2.sh" zum Beenden des Terminators. Dann hat die Run-Funktion die Möglichkeit, Ihren Teminator zu verlassen.

    #! /bin/sh
    # use . run2.sh

    run()
    {
        echo "this is run"
        #return 0
        exit 0
    }

    echo "this is begin"
    run
    echo "this is end"

Wie auch immer, ich stimme Kaz zu, es ist ein Designproblem.

Umae
quelle
Aus dem Text ist nicht klar, was diese Antwort zu tun versucht, aber sie löst die vorliegende Frage sicherlich nicht.
Luís de Sousa
2

Ich hatte das gleiche Problem und aus den obigen Antworten und aus dem, was ich verstand, was letztendlich für mich funktionierte, war:

  1. Haben Sie eine Shebang-Zeile, die das beabsichtigte Skript aufruft, zum Beispiel:

    #!/bin/bashwird verwendet bash, um das Skript auszuführen

Ich habe Skripte mit beiden Arten von Shebang. Aus diesem Grund war die Verwendung von shoder .nicht zuverlässig, da dies zu einer Fehlausführung führte (z. B. wenn das Skript unvollständig ausgeführt wird).

Die Antwort war daher

    • Stellen Sie sicher, dass das Skript einen Shebang hat, damit kein Zweifel an dem beabsichtigten Handler besteht.
    • chmod die .sh-Datei, damit sie ausgeführt werden kann. (chmod +x file.sh)
    • Rufen Sie es direkt ohne shoder auf.

      (./myscript.sh)

Hoffe das hilft jemandem mit ähnlichen Fragen oder Problemen.

gk_2000
quelle
1

Ich denke, dass dies passiert, weil Sie es im Quellmodus mit dem Punkt ausführen

. myscript.sh

Sie sollten das in einer Subshell ausführen:

/full/path/to/script/myscript.sh

'source' http://ss64.com/bash/source.html

JBoy
quelle
Sie benötigen keinen vollständigen Pfad zum Skript, wenn dies . myscript.shfunktioniert. Möglicherweise benötigen Sie höchstens ./myscript.sh.
Álvaro González
1

Es ist richtig, dass Sourcing- oder ausgeführte Skripte returnvs. verwenden exit, um dieselbe Sitzung offen zu halten, wie andere angemerkt haben.

Hier ist ein verwandter Tipp, wenn Sie jemals ein Skript möchten, das die Sitzung offen hält, unabhängig davon, ob es aus einer Quelle stammt oder nicht.

Das folgende Beispiel kann direkt wie / foo.shoder wie . foo.sh/ ausgeführt werden source foo.sh. In beiden Fällen bleibt die Sitzung nach dem "Beenden" geöffnet. Die $@Zeichenfolge wird übergeben, damit die Funktion auf die Argumente des äußeren Skripts zugreifen kann.

#!/bin/sh
foo(){
    read -p "Would you like to XYZ? (Y/N): " response;
    [ $response != 'y' ] && return 1;
    echo "XYZ complete (args $@).";
    return 0;
    echo "This line will never execute.";
}
foo "$@";

Endergebnis:

$ foo.sh $ Möchtest
du XYZ? (J / N): n
$. foo.sh
$ Möchten Sie XYZ? (J / N): n
$ |
(Terminalfenster bleibt geöffnet und akzeptiert zusätzliche Eingaben)

Dies kann nützlich sein, um Skriptänderungen in einem einzelnen Terminal schnell zu testen, während eine Menge Schrottcode unter dem Haupt- exit/ returnwährend der Arbeit bleibt. Es könnte Code in gewisser Weise auch portabler machen (wenn Sie Tonnen von Skripten haben, die möglicherweise auf unterschiedliche Weise aufgerufen werden oder nicht), obwohl es viel weniger umständlich ist, sie nur zu verwenden returnund exitgegebenenfalls.

Beejor
quelle
0

Wenn Ihr Terminalemulator nicht über -holdein Skript verfügt, können Sie ein Sourcing-Skript bereinigen und das Terminal mit folgenden Funktionen halten:

#!/bin/sh
sed "s/exit/return/g" script >/tmp/script
. /tmp/script
read

sonst kannst du verwenden $TERM -hold -e script

Technosaurus
quelle
0

Stellen Sie außerdem sicher, dass Sie mit dem erwarteten Rückgabewert zurückkehren. Wenn Sie exit verwenden, wenn Sie auf ein Exit stoßen, wird es aus Ihrer Basis-Shell beendet, da die Quelle keinen anderen Prozess (keine Instanz) erstellt.

coder23
quelle
0

Um ein Skript zu schreiben , das sicher ist , ausgeführt werden entweder als ein Shell - Skript oder als RC - Datei stammen, kann das Skript überprüfen und vergleichen , $0und , $BASH_SOURCEund festzustellen , ob exitsicher verwendet werden kann.

Hier ist ein kurzer Code-Ausschnitt dafür

[ "X$(basename $0)" = "X$(basename $BASH_SOURCE)" ] && \
    echo "***** executing $name_src as a shell script *****" || \
    echo "..... sourcing $name_src ....."
Tzunghsing David Wong
quelle
-1

1) exit 0 wird aus dem Skript entfernt, wenn es erfolgreich ist.

2) Exit 1 wird aus dem Skript entfernt, wenn es ein Fehler ist.

Sie können diese beiden oben genannten basierend auf ur req versuchen.

Teja
quelle