Ritorno implicito nelle funzioni bash?

Supponiamo di avere una funzione bash in questo modo:

gmx(){ echo "foo"; } 

questa funzione sarà implicita restituire il valore di uscita del comando echo o è necessario utilizzare return?

gmx(){ echo "foo"; return $? } 

presumo che il modo bash funziona, lo stato di uscita del comando finale della funzione bash è quello che viene “restituito”, ma non certo al 100%.

Risposta

return restituisce esplicito da una funzione di shell o” dot script “(uno script originato). Se return non viene eseguito, viene eseguito un ritorno implicito alla fine della funzione shell o del dot script.

Se return viene eseguito senza un parametro, equivale a restituire lo stato di uscita del comando eseguito più di recente.

Ecco come funziona return in tutti i POSIX shell.

Ad esempio,

gmx () { echo "foo" return "$?" } 

è quindi equivalente a

gmx () { echo "foo" return } 

che è uguale a

gmx () { echo "foo" } 

In generale, è molto raro che tu abbia bisogno di utilizzare $? affatto. È davvero necessario solo se è necessario salvarlo per un utilizzo futuro, ad esempio se è necessario indagare più volte sul suo valore (nel qual caso si assegnerebbe il suo valore a una variabile ed eseguire una serie di test su quella variabile).

Commenti

  • Uno svantaggio dellutilizzo di return è che per funzioni definite come f() (...; cmd; return), impedisce lottimizzazione eseguita da alcune shell per eseguire cmd nello stesso processo della subshell. Con molte shell, ciò significa anche che lo stato di uscita della funzione non ‘ porta le informazioni che cmd è stato terminato quando è stato (la maggior parte delle shell può ‘ recuperare comunque tali informazioni).
  • Nota che con pdksh e alcuni dei suoi derivati (come OpenBSD sh o posh), ‘ avresti bisogno di return -- "$?" se cera un possibilità che lultimo comando fosse una funzione che ha restituito un numero negativo. mksh (basato anche su pdksh) vieta alle funzioni di restituire valori negativi.
  • grazie per laiuto, immagino di non ‘ per capire come return x funzioni in modo diverso da exit x … lunica cosa che so è che return x non uscirà dal processo corrente.
  • @AlexanderMills Bene, ‘ è quello che ho detto: return viene utilizzato per tornare da una funzione o da uno script punto. exit fa qualcosa di completamente diverso (termina un processo).
  • sì, ha senso, penso che sto iniziando a capire meglio questo

Risposta

Dalla pagina man bash(1):

Quando viene eseguito, lo stato di uscita di una funzione è lo stato di uscita dellultimo comando eseguito nel corpo.

Commenti

  • giusto, e un corollario potrebbe essere che listruzione return non è altro che lo stato di uscita?
  • Immagino return è un comando incorporato, sebbene return 1 sia diverso da exit 1, ecc.
  • ” return [n]: fa sì che una funzione interrompa lesecuzione e restituisca il valore specificato da n al suo chiamante. Se n viene omesso, lo stato di ritorno è quello dellultimo comando eseguito nel corpo della funzione. ” (ibid) Quindi, return forza lo stato di uscita di una funzione a un valore specifico, se specificato.
  • @AlexandwrMills Sì, return e exit sono entrambi integrati, eccetto che return può essere utilizzato solo allinterno della funzione. Non puoi ‘ terminare uno script con return. Lo stato di uscita è il valore restituito dal comando. return è il comando che restituisce quel valore. Quindi listruzione ” return non è altro che lo stato di uscita ” non è abbastanza preciso. Uno è un valore, laltro è il comando più il valore.
  • @AlexanderMills, return restituisce dalla funzione, exit esce dallintera shell. ‘ è esattamente uguale a, ad esempio C con return e exit(n), o return e sys.exit() in Python.

Risposta

Aggiungerò solo alcune note di cautela alle risposte già fornite:

  • Anche se return ha un significato molto speciale per la shell, dal punto di vista della sintassi è un comando incorporato della shell e unistruzione return viene analizzato come qualsiasi altro comando semplice. Quindi, ciò significa che come nellargomento di qualsiasi altro comando, $? se non quotato, sarebbe soggetto a split + glob

    Quindi devi citarne $? per evitarlo:

    return "$?" 
  • return di solito non “accetta alcuna opzione (ksh93” s accetta il solito --help, --man, --author … però). Lunico argomento che si aspetta (facoltativo) è il codice di ritorno. Lintervallo di codici di ritorno accettati varia da shell a shell e se qualsiasi valore al di fuori di 0..255 si riflette correttamente in

varia anche da shell a shell. Vedi Codice di uscita predefinito quando il processo viene terminato? per i dettagli.

La maggior parte delle shell accetta numeri negativi (dopotutto, largomento passato a la _exit() / exitgroup() chiamata di sistema è una int, quindi con valori che comprendono almeno – 2 31 a 2 31 -1, quindi ha senso che le shell accettino lo stesso intervallo per le sue funzioni).

La maggior parte delle shell usa il waitpid() e co. API per recuperare lo stato di uscita, tuttavia, in tal caso, viene troncato a un numero compreso tra 0 e 255 quando memorizzato in $?. Anche se si richiama una funzione non comporta la generazione di un processo e utilizza waitpid() per recuperare il suo stato di uscita poiché tutto viene eseguito nello stesso processo, molte shell imitano anche questo waitpid() comportamento durante la chiamata di funzioni. Ciò significa che anche se chiami return con un valore negativo, $? conterrà un numero positivo.

Ora, tra quelle shell la cui return accetta numeri negativi (ksh88, ksh93, bash, zsh, pdksh e derivati diversi da mksh, yash), ce ne sono alcuni ( pdksh e yash) che richiedono che sia scritto come return -- -123 altrimenti -123 viene considerato come tre -1, -2, -3 opzioni non valide.

Come pdksh e il suo de i rivativi (come OpenBSD sh o posh) conservano il numero negativo in $?, che significa che fare return "$?" fallirebbe quando $? contiene un numero negativo (cosa che accadrebbe quando lultimo comando eseguito era una funzione che restituiva un numero negativo ).

Quindi return -- "$?" sarebbe meglio con quelle shell. Tuttavia si noti che sebbene supportata dalla maggior parte delle shell, tale sintassi non è POSIX e in pratica non è supportata da mksh e dai derivati di ash.

Quindi, per riassumere, con shell basate su pdksh, puoi utilizzare numeri negativi negli argomenti delle funzioni, ma se lo fai, return "$@" non funzionerà. In altre shell, return "$@" funzionerà e dovresti evitare di utilizzare numeri negativi (o numeri al di fuori di 0..255) come argomenti per return.

  • In tutte le shell che conosco, chiamare return dallinterno di una subshell in esecuzione allinterno di una funzione causerà luscita della subshell (con lo stato di uscita fornito se presente o quello dellultimo comando run), ma altrimenti non causerà un ritorno dalla funzione (per me, non è chiaro se POSIX ti dà quella garanzia, alcuni sostengono che exit dovrebbe essere usato al posto delle subshell di uscita funzioni interne). Ad esempio

    f() { (return 3) echo "still inside f. Exit status: $?" } f echo "f exit status: $?" 

    restituirà:

    still inside f. Exit status: 3 f exit status: 0 
  • Risposta

    Sì, il valore di ritorno implicito di una funzione è lo stato di uscita dellultima eseguita . Questo vale anche in qualsiasi punto di qualsiasi script di shell. In qualsiasi punto della sequenza di esecuzione dello script, lo stato di uscita attuale è lo stato di uscita dellultimo comando eseguito. Comando pari eseguito come parte dellassegnazione di una variabile: var=$(exit 34). La differenza con le funzioni è che una funzione potrebbe cambiare lo stato di uscita alla fine dellesecuzione della funzione.

    Il modo alternativo per cambiare lo “stato di uscita attuale” è avviare una sub shell e uscirne con qualsiasi stato di uscita necessario:

    $ $(exit 34) $ echo "$?" 34 

    E sì, lo stato di uscita espansione deve essere citato:

    $ IFS="123" $ $(exit 34) $ echo $? 4 

    Un (exit 34) funziona anche.
    Alcuni potrebbero sostenere che un costrutto più robusto dovrebbe essere $(return 34) e che unuscita dovrebbe “uscire” dallo script in esecuzione. Tuttavia, $(return 34) non funziona con qualsiasi versione di bash. Quindi, non è portabile.

    Il modo più sicuro per impostare uno stato di uscita è usarlo poiché è stato progettato per funzionare, definire e return da una funzione :

    exitstatus(){ return "${1:-"$?"}"; } 

    Quindi, alla fine di una funzione. è esattamente equivalente a non avere niente o return o return "$?". La fine di una funzione non deve necessariamente significare “lultima riga di codice di una funzione”.

    #!/bin/sh exitstatus(){ a="${1:-"$?"}"; return "$a"; } gmx(){ if [ "$1" = "one" ]; then printf "foo "; exitstatus 78 return "$?" elif [ "$1" = "two" ]; then printf "baz "; exitstatus 89 return else printf "baz "; exitstatus 90 fi } 

    Stamperà:

    $ ./script foo 78 baz 89 baz 90 

    Lunico utilizzo pratico di "$?" è stamparne il valore: echo "$?" o memorizzare in una variabile (poiché è un valore effimero e cambia ad ogni comando eseguito): exitstatus=$? (ricordati di citare la variabile in comandi come export EXITSTATUS="$?".

    Nel comando return, lintervallo di valori valido è generalmente compreso tra 0 e 255, ma tieni presente che i valori di 126 + n sono usati da alcune shell per segnalare uno stato di uscita speciale, quindi la raccomandazione generale è di usare 0-125.

    Lascia un commento

    Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *