Qualsiasi modo per uscire dallo script bash, ma non uscire dal terminale


183

Quando uso exit comando in uno script di shell, lo script termina il terminale (il prompt). C'è un modo per terminare uno script e quindi rimanere nel terminale?

La mia sceneggiatura run.shCi si aspetta che la venga eseguita direttamente o proveniente da un'altra sceneggiatura.

EDIT: per essere più specifici, ci sono due script run2.shcome

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

e run.shcome

...
exit
...

quando lo eseguo . run2.sh, e se ha colpito il exitcodicerun.sh , voglio che si fermi al terminale e rimanga lì. Ma usando exit, l'intero terminale viene chiuso.

PS: ho provato a usare return, ma la echocodeline verrà comunque eseguita ....


5
Devo davvero, davvero, chiederti: perché stai usando exit in uno script di provenienza?
Ignacio Vazquez-Abrams,

3
il comando exit non deve terminare la sessione / login del terminale. se usi exit 0per terminare lo script dopo il successo, quando esegui lo script ex: ./test.shdovresti vedere l'output ma la tua console rimarrà aperta.
Ben Ashton,

È possibile utilizzare il shellcomando, che in effetti apre un terminale shell. La mia esperienza personale è tuttavia che ciò non accade exit. Exit normalmente restituisce il controllo allo script principale.
Willem Van Onsem,

Risposte:


258

Il "problema" è che stai acquistando e non eseguendo lo script. Quando si esegue l'origine di un file, il suo contenuto verrà eseguito nella shell corrente, anziché generare una subshell. Quindi tutto, inclusa l'uscita, influenzerà la shell corrente.

Invece di usare exit, vorrai usare return.


2
Ecco un'altra spiegazione che ho trovato utile: askubuntu.com/a/53179/148337
3cheesewheel

Sebbene sia corretta, questa non è un'ottima risposta. Ignora che lo script chiamante può dichiarare le variabili o le funzioni a cui ha bisogno di accedere allo script chiamato. Meglio spiegare come impostare un codice di ritorno e quindi elaborarlo in runs.sh@ruakh ha la risposta migliore a questa domanda.
MikeSchinkel,

5
Cosa succede se la funzione è una chiamata nidificata? cioè a chiama b, b chiama c, c vuole uscire immediatamente a e b.
Michael,

La fonte è quasi la stessa di copia incolla. È meglio usare sh <script>o bash <script>se si desidera eseguire uno script e terminare ad un certo punto
peterchaula

42

Sì; puoi usare al returnposto diexit . Il suo scopo principale è quello di tornare da una funzione di shell, ma se lo usi all'interno di uno sourcescript -d, ritorna da quello script.

Come dice §4.1 "Bourne Shell Builtins" del Manuale di riferimento di Bash :

     return [n]

Fa uscire una funzione shell con il valore di ritorno n . Se n non viene fornito, il valore restituito è lo stato di uscita dell'ultimo comando eseguito nella funzione. Questo può anche essere usato per terminare l'esecuzione di uno script in esecuzione con .(o source) incorporato, restituendo n oppure lo stato di uscita dell'ultimo comando eseguito all'interno dello script come stato di uscita dello script. Qualsiasi comando associato alla RETURNtrap viene eseguito prima che l'esecuzione riprenda dopo la funzione o lo script. Lo stato di ritorno è diverso da zero se returnviene utilizzato al di fuori di una funzione e non durante l'esecuzione di uno script da .o source.


3
returnpuò essere utilizzato SOLO da una funzione. Se lo usi returne lo esegui come uno script di shell (ad es. sh run.sh), Bash segnalerà un errore - return: can only ritorna "da una funzione o da uno script di provenienza"
Tzunghsing David Wong,

@TzungsingDavidWong: ti rendi conto che la maggior parte di questa risposta è una citazione dal manuale di riferimento ufficiale? E che il messaggio di errore che citi concorda con questa risposta anziché con la tua richiesta?
Ruakh,

Non sono in disaccordo con te. Voglio semplicemente sottolineare che returnnon funzionerà se lo script viene eseguito come script shell e non eseguito da. (o source). A proposito, dove posso trovare il documento source -d?
Tzunghsing David Wong,

9

Invece di eseguire lo script utilizzando . run2.sh, è possibile eseguirlo utilizzando sh run2.shobash run2.sh

Verrà avviata una nuova shell secondaria, per eseguire quindi lo script, verrà chiusa alla fine dello script lasciando l'altra shell aperta.


Se è così, allora perché il secondo parametro sh "." run2.sh?
CHAN,

@ H0WARD Hai ragione, ho dimenticato di rimuovere i punti. Ho modificato la risposta ora.
Viorel Mirea,

1
L'OP afferma esplicitamente la fonte come requisito.
Jonathan Neufeld,

4

È possibile aggiungere un comando di uscita aggiuntivo dopo l'istruzione / comando return in modo che funzioni per entrambi, eseguendo lo script dalla riga di comando e approvvigionamento dal terminale.

Esempio di codice di uscita nello script:

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

La riga con il exitcomando non verrà chiamata quando si esegue lo script dopo il returncomando.

Quando si esegue lo script, il returncomando fornisce un errore. Quindi, eliminiamo il messaggio di errore inoltrandolo a /dev/null.


3

In realtà, penso che potresti essere confuso da come si spinge run a script .

Se usi shper eseguire uno script, diciamo sh ./run2.sh, anche se lo script incorporato terminaexit , la finestra del terminale rimarrà comunque.

Tuttavia se si utilizza .osource , la finestra del terminale verrà chiusa / chiusa anche al termine dell'abbonamento.

per maggiori dettagli, fare riferimento a Qual è la differenza tra l'utilizzo di she source?


2

Questo è proprio come hai inserito una funzione di esecuzione nello script run2.sh. Si utilizza il codice di uscita all'interno di run mentre si esegue il sorgente del file run2.sh in bash tty. Se la funzione dà alla corsa ha il potere di uscire dallo script e dà a run2.sh il potere di uscire dal terminatore. Quindi, perché la funzione di esecuzione ha il potere di uscire dal tuo termostato.

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

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

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

Ad ogni modo, approvo che Kaz sia un problema di progettazione.


Dal testo non è chiaro cosa tenti di fare questa risposta, ma certamente non risolve la domanda.
Luís de Sousa il

2

Ho avuto lo stesso problema e dalle risposte sopra e da quello che ho capito ciò che alla fine ha funzionato per me è stato:

  1. Avere una riga shebang che invoca lo script previsto, ad esempio,

    #!/bin/bashusa bashper eseguire lo script

Ho degli script con entrambi i tipi di shebang. Per questo motivo, l'utilizzo sho .non era affidabile, in quanto porta a una cattiva esecuzione (come quando lo script viene eseguito in modo incompleto)

La risposta quindi era

    • Assicurati che la sceneggiatura abbia un shebang, in modo che non ci siano dubbi sul gestore previsto.
    • chmod il file .sh in modo che possa essere eseguito. (chmod +x file.sh)
    • Richiamare direttamente senza sho.

      (./myscript.sh)

Spero che questo aiuti qualcuno con una domanda o un problema simile.


1

Penso che ciò accada perché lo stai eseguendo in modalità sorgente con il punto

. myscript.sh

Dovresti eseguirlo in una subshell:

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

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


Non è necessario il percorso completo per lo script se . myscript.shfunziona. Al massimo, potresti aver bisogno ./myscript.sh.
Álvaro González,

1

È corretto che gli script di provenienza e quelli eseguiti utilizzino returnvs. exitper mantenere aperta la stessa sessione, come altri hanno notato.

Ecco un suggerimento correlato, se si desidera uno script che dovrebbe tenere aperta la sessione, indipendentemente dal fatto che sia o meno di provenienza.

L'esempio seguente può essere eseguito direttamente come foo.sho come . foo.sh/ source foo.sh. Ad ogni modo, manterrà la sessione aperta dopo "uscire". La $@stringa viene passata in modo che la funzione abbia accesso agli argomenti dello script esterno.

#!/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 "$@";

Risultato terminale:

$ foo.sh
$ Vuoi XYZ? (S / N): n
$. foo.sh
$ Vuoi XYZ? (S / N): n
$ |
(la finestra del terminale rimane aperta e accetta input aggiuntivi)

Questo può essere utile per testare rapidamente le modifiche agli script in un singolo terminale mantenendo un sacco di codice di scarto sotto il main exit/ returnmentre lavori. Potrebbe anche rendere il codice più portabile in un certo senso (se hai tonnellate di script che possono o non possono essere chiamati in modi diversi), anche se è molto meno ingombrante da usare returne exitdove appropriato.


0

se il tuo emulatore di terminale non ha -hold, puoi disinfettare uno script di provenienza e tenere il terminale con:

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

altrimenti puoi usare $TERM -hold -e script


0

Assicurati anche di restituire con il valore di ritorno atteso. Altrimenti se usi exit quando incontrerai un'uscita, uscirà dalla shell di base poiché il sorgente non crea un altro processo (istanza).


0

Per scrivere uno script che è sicuro per essere eseguito come uno script di shell o di provenienza come file rc, lo script può verificare e confrontare $0ed $BASH_SOURCEe determinare se exitpuò essere utilizzato in modo sicuro.

Ecco uno snippet di codice breve per questo

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

-1

1) l'uscita 0 uscirà dallo script se ha esito positivo.

2) l'uscita 1 uscirà dallo script se si verifica un errore.

Puoi provare questi sopra due in base a ur req.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.