Differenza tra ritorno e uscita nelle funzioni Bash


429

Qual è la differenza tra l' istruzione returne exitnelle funzioni di Bash rispetto ai codici di uscita?


55
Protip: digita la help <command>tua shell per ottenere informazioni su cosa farà un built-in della shell. Nel tuo caso help returnehelp exit
SiegeX il

Risposte:


318

Da man bashsu return [n];

Fa interrompere l'esecuzione di una funzione e restituisce il valore specificato da n al suo chiamante. Se n viene omesso, lo stato di ritorno è quello dell'ultimo comando eseguito nel corpo della funzione.

... su exit [n]:

Fa uscire la shell con uno stato di n. Se n viene omesso, lo stato di uscita è quello dell'ultimo comando eseguito. Una trap su EXIT viene eseguita prima che la shell termini.

MODIFICARE:

Secondo la modifica della domanda, per quanto riguarda i codici di uscita, returnnon ha nulla a che fare con i codici di uscita. I codici di uscita sono destinati ad applicazioni / script , non a funzioni. Quindi, a questo proposito, l'unica parola chiave che imposta il codice di uscita dello script (quella che può essere catturata dal programma chiamante usando la $?variabile shell) è exit.

MODIFICA 2:

La mia ultima dichiarazione di riferimento exitsta causando alcuni commenti. È stato fatto per differenziare returne exitper la comprensione dell'OP, e in effetti, in un dato punto di uno script programma / shell, exitè l'unico modo per terminare lo script con un codice di uscita al processo chiamante.

Ogni comando eseguito nella shell produce un "codice di uscita" locale: imposta la $?variabile di quel codice, e può essere utilizzato con if, &&e altri operatori ai condizionale eseguire altri comandi.

Questi codici di uscita (e il valore della $?variabile) vengono ripristinati da ogni esecuzione del comando.

Per inciso, il codice di uscita dell'ultimo comando eseguito dallo script viene utilizzato come codice di uscita dello script stesso come visto dal processo di chiamata.

Infine, le funzioni, quando chiamate, agiscono come comandi di shell rispetto ai codici di uscita. Il codice di uscita della funzione ( all'interno della funzione) viene impostato utilizzando return. Pertanto, quando return 0viene eseguita una funzione , l'esecuzione della funzione termina, fornendo un codice di uscita pari a 0.


10
Non esattamente. Restituisce sempre un valore dalla shell corrente. Non importa se ci si trova all'interno di una funzione o meno.
Diego Sevilla,

10
Commenta la tua modifica: potrei confondere i valori di ritorno e i codici di uscita, ma func(){ return 50; };func;echo $?riecheggia 50. Quindi la $?variabile shell non sembra essere limitata a exit.
lecodesportif,

8
"Si $?espande allo stato di uscita della pipeline in primo piano eseguita più di recente." Tale uscita può provenire dalla shell sotto forma di una chiamata exit(o colpire la fine dello script) o sotto forma di una chiamata returnall'interno di una funzione.
SiegeX,

11
@lecodesportif: $? il processo / script corrente è limitato exito al risultato dell'ultimo comando eseguito da questo script. Quindi, se la tua ultima riga di script è la chiamata a quella funzione e quella funzione restituisce 50, sì, $?quello che produci nel processo che ti ha chiamato è 50. Tuttavia, ciò non ha a che fare con il return, perché questo è limitato allo script corrente. Succede di essere restituito solo se questa chiamata di funzione è l'ultima frase dello script. exittuttavia, completare sempre lo script e restituire quel valore per quanto $? riguarda il processo di chiamata .
Diego Sevilla,

11
-1 per avermi confuso con la riga " returnnon ha nulla a che fare con i codici di uscita". La sperimentazione mi dice che non esiste alcuna differenza funzionale tra il codice di ritorno di una funzione e il codice di uscita di uno script.
Jack,

296

returnfarà sì che la funzione corrente esca dall'ambito, mentre exitfarà terminare lo script nel punto in cui viene chiamato. Ecco un programma di esempio per spiegare questo:

#!/bin/bash

retfunc()
{
    echo "this is retfunc()"
    return 1
}

exitfunc()
{
    echo "this is exitfunc()"
    exit 1
}

retfunc
echo "We are still here"
exitfunc
echo "We will never see this"

Produzione

$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()

17
Bell'esempio Puoi anche mostrare il valore di uscita di 1 in $?.
Diego Sevilla,

48
Nota che questa funzione NON stampa "Siamo ancora qui" se aggiungi "set -e" prima della chiamata a "retfunc".
Michael,

4
Tuttavia, echo fnord | while read x; do exitfunc; done; echo "still here"verrà stampato "ancora qui". Sembra che solo la whilesotto-shell sia uscita in questo scenario.
Tripleee,

Una soluzione approssimativa è done || exit $?che è brutta e non esattamente equivalente.
Tripleee,

2
+1 Potrebbe essere utile aggiungere: `` returnfarà sì che la funzione corrente o lo script di provenienza vadano fuori dall'ambito ''.
Isaac,

56

Non credo che nessuno abbia veramente risposto completamente alla domanda perché non descrivono come vengono usati i due. OK, penso che sappiamo che exit uccide lo script, dovunque venga chiamato e puoi assegnargli uno stato come exit o exit 0 o exit 7 e così via. Questo può essere usato per determinare come lo script è stato costretto a fermarsi se chiamato da un altro script ecc. Basta all'uscita.

return quando chiamato restituirà il valore specificato per indicare il comportamento della funzione, generalmente un 1 o uno 0. Ad esempio:

    #!/bin/bash
    isdirectory() {
      if [ -d "$1" ]
      then
        return 0
      else
        return 1
      fi
    echo "you will not see anything after the return like this text"
    }

controlla in questo modo:

    if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi

o in questo modo:

    isdirectory || echo "not a directory"

In questo esempio, il test può essere utilizzato per indicare se la directory è stata trovata. notare che qualsiasi cosa dopo il ritorno non verrà eseguita nella funzione. 0 è vero ma falso è 1 nella shell, diverso dagli altri linguaggi prog.

Per maggiori informazioni sulle funzioni: http://www.linuxjournal.com/content/return-values-bash-functions

NOTA: la funzione isdirectory è solo a scopo didattico. Questo non dovrebbe essere il modo in cui esegui tale opzione in uno script reale.


3
O semplicemente usare test -d $1per ottenere lo stesso risultato. Non farlo mai if <check> return else return. <check>da solo farà la stessa cosa in tutte le lingue che conosco almeno.
erikbwork,

4
Per essere ancora più esplicito su ciò che sta dicendo erik: isdirectory() { [ -d "$1" ]; }si comporterà esattamente come quello che hai qui: il valore di ritorno predefinito di una funzione shell, sia raggiungendo la fine del suo codice sia con un returnsenza argomenti, è quello del comando più recente.
Charles Duffy,

11
Gli altri commentatori qui stanno criticando lo stile dell'esempio di Mike Q, quando in realtà sta parlando del comportamento returndell'affermazione. È vero che il suo esempio è semplicistico e non può essere usato in produzione. Ma è semplice, quindi svolge perfettamente il suo compito. Niente di sbagliato.
Mike S,

Grazie Mike S, sì, sono d'accordo che l'esempio più semplice spiega meglio l'uscita contro il ritorno. Gli altri commenti sono certamente validi e dovrebbero essere considerati per programmatori bash più avanzati ;-)
Mike Q

1
Qualcuno potrebbe dire che non è esattamente correlato alla domanda, ma si riferiva e ha risposto al problema che avevo che mi ha portato a trovare questa domanda. :-)
Jesse Steele,

33

Ricorda, le funzioni sono interne a uno script e normalmente ritornano da dove sono state chiamate usando l'istruzione return. La chiamata di uno script esterno è completamente un'altra questione e gli script di solito terminano con un'istruzione exit.

La differenza "tra l'istruzione return e exit nelle funzioni BASH rispetto ai codici di uscita" è molto piccola. Entrambi restituiscono uno stato, non valori di per sé. Uno stato zero indica il successo, mentre qualsiasi altro stato (da 1 a 255) indica un errore. L'istruzione return tornerà allo script da dove è stata chiamata, mentre l'istruzione exit finirà l'intero script da dove viene incontrata.

return 0  # returns to where the function was called.  $? contains 0 (success).

return 1  # returns to where the function was called.  $? contains 1 (failure).

exit 0  # exits the script completely.  $? contains 0 (success).

exit 1  # exits the script completely.  $? contains 1 (failure).

Se la tua funzione termina semplicemente senza alcuna dichiarazione di ritorno, lo stato dell'ultimo comando eseguito viene restituito come codice di stato (e verrà inserito $?).

Ricorda, return e exit restituiscono un codice di stato da 0 a 255, disponibile in $?. Non è possibile inserire altro in un codice di stato (ad es. Return "cat"); non funzionerà. Tuttavia, uno script può restituire 255 diversi motivi di errore utilizzando i codici di stato.

È possibile impostare le variabili contenute nello script chiamante o ottenere risultati echo nella funzione e utilizzare la sostituzione dei comandi nello script chiamante; ma lo scopo di return e exit è passare codici di stato, non valori o risultati di calcolo come ci si potrebbe aspettare in un linguaggio di programmazione come C.


25

A volte, esegui uno script usando .o source.

. a.sh

Se si include un exitin a.sh, non solo terminerà lo script, ma terminerà la sessione della shell.

Se includi a returnin a.sh, semplicemente interrompe l'elaborazione dello script.


1
Ma quando eseguo a.sh ricevo un errore return: can only 'return' from a function or sourced script, il che lo rende inadatto per uno script generale.
Peter - Ripristina Monica il

Al massimo livello in uno script, nessuno dei due è adatto in allsituazioni. Usare .o sourceeseguire lo script nella shell corrente, anziché generare una sotto-shell. Lo script deve sapere come deve essere utilizzato. Guai all'utente che lo fa di fronte. Personalmente, consiglio di leggere gli script prima di eseguirli la prima volta.
Jesse Chisholm,

3
Un trucco fantastico in cui mi sono imbattuto è utilizzare una trapfunzione per ERR EXITe quindi prima salvare il codice di uscita di un comando non riuscito errCode=$?e quindi uscire dallo script (di provenienza o meno) con return $errCode || exit $errCodedove ||significa "se non posso tornare perché non ero di provenienza , basta uscire invece ".
dragon788,

6

In parole semplici (principalmente per i principianti nella codifica), possiamo dire,

`return` : exits the function,
`exit()` : exits the program(called as process while running)

Anche se hai osservato, questo è molto semplice ma ...,

`return` : is the keyword
`exit()` : is the function

1
In uno script bash, exitnon è più o meno una funzione di return. Sono comandi integrati. Non sono nemmeno parole riservate.
Peter - Ripristina Monica il

6
  • exitterminare il processo corrente ; con o senza codice di uscita, considera questo un sistema più che una funzione di programma. Si noti che durante l'approvvigionamento, exitla shell terminerà, tuttavia, quando in esecuzione sarà solo exitlo script.

  • returnda una funzione tornare all'istruzione dopo la chiamata, con o senza un codice di ritorno. returnè facoltativo ed è implicito alla fine della funzione. returnpuò essere utilizzato solo all'interno di una funzione.

Voglio aggiungere che, pur essendo di provenienza, non è facile per exitlo script all'interno di una funzione senza uccidere la shell. Penso che un esempio sia migliore in uno script "test"

#!/bin/bash
function die(){
   echo ${1:=Something terrible wrong happen}
   #... clean your trash
   exit 1
}

[ -f /whatever/ ] || die "whatever is not available"
# now we can proceed
echo "continue"

facendo quanto segue:

user$ ./test
Whatever is not available
user$

test - e - la shell si chiuderà.

user$ . ./test
Whatever is not available

solo testfinirà e il prompt mostrerà.

La soluzione è racchiudere la potenziale procedura in (e)

#!/bin/bash
function die(){
   echo $(1:=Something terrible wrong happen)
   #... clean your trash
   exit 1
}

( # added        
    [ -f /whatever/ ] || die "whatever is not available"
    # now we can proceed
    echo "continue"
) # added

ora, in entrambi i casi, testuscirà solo .


Aggiungendo (e )inserisce quel blocco in una sotto-shell, annullando effettivamente il .comando (source) come se avessi eseguito normalmente lo script di test, che si trova in una sotto-shell. IO se lo script non viene eseguito .o sourceallora hai effettivamente 2 sub-shell.
Jesse Chisholm,

3

La domanda del PO: Qual è la differenza tra l'istruzione return e exit nelle funzioni BASH rispetto ai codici d'uscita?

In breve, sono necessari alcuni chiarimenti:

  • Non è richiesta un'istruzione (return | exit) per terminare l'esecuzione di una (funzione | shell). Una (funzione | shell) termina quando raggiunge la fine del suo elenco di codici, anche senza alcuna istruzione (return | exit).
  • Un'istruzione (return | exit) non è richiesta per restituire un valore da una terminata (funzione | shell). Ogni processo ha una variabile incorporata $? che ha sempre un valore numerico. È una variabile speciale che non può essere impostata come "? = 1", ma è impostata solo in modi speciali (vedi sotto *). Il valore di $? dopo l'ultimo comando da eseguire nella (chiamata funzione | shell secondaria) è il valore che viene restituito alla (funzione chiamante | shell padre). Questo è vero se l'ultimo comando eseguito è ("return [n]" | "exit [n]") o plain ("return" o qualcos'altro che sembra essere l'ultimo comando nel codice delle funzioni chiamate.

Nell'elenco elenco sopra, scegliere tra "(x | y)" o sempre il primo elemento o sempre il secondo elemento per ottenere rispettivamente istruzioni su funzioni e ritorno o shell e uscita.

Ciò che è chiaro è che entrambi condividono l'uso comune della variabile speciale $? per passare valori verso l'alto dopo che terminano.

* Ora per i modi speciali che $? può essere impostato:

  • Quando una funzione chiamata termina e ritorna al suo chiamante allora $? nel chiamante sarà uguale al valore finale di $? nella funzione terminata.
  • Quando una shell genitore attende in modo implicito o esplicito su una singola sub shell e viene rilasciata al termine di quella sub shell, allora $? nella shell genitore sarà uguale al valore finale di $? nella sub shell terminata.
  • Alcune funzioni integrate possono modificare $? a seconda del loro risultato. Ma alcuni non lo fanno.
  • Funzioni integrate "return" e "exit", quando seguite da un argomento numerico sia $? con argomento e termina l'esecuzione.

Vale la pena notare che $? può essere assegnato un valore chiamando exit in una sub shell, in questo modo:

# (exit 259)
# echo $?
3  

4
Nel caso in cui qualcuno lo abbia mancato, exit 259echo come 3perché il valore finale di uscita è un singolo byte. 259 % 256 = 3
Jesse Chisholm,

0

Prima di tutto, returnè una parola chiave e il exitmio amico è una funzione.

Detto questo, ecco una spiegazione più semplice.

return Restituisce un valore da una funzione.

exit Esce o abbandona la shell corrente.


Non proprio! Sei logicamente sbagliato. Exit è una funzione mentre returnè una parola chiave. Il ritorno è molto più di un semplice codice di uscita, motivo per cui il confronto non è corretto.
Ahmad Awais,

L'ho modificato per rendere più chiaro il punto che stavo cercando di chiarire. Grazie per avermi aiutato a farlo.
Ahmad Awais,

4
Né sono exitreturn"parole chiave", né, come le chiama il manuale bash, "parole riservate". Nessuno dei due è una "funzione", nel senso di una funzione bash. Entrambi sono comandi integrati, in gergo bash. ( V'è una funzione di libreria C standard chiamato exit(), e il linguaggio di programmazione C ha una parola riservata return, ma questi non devono essere confuse con i comandi bash, anche se i loro semantica è curiosamente simile.)
Peter - Ripristinare Monica
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.