2012-03-27 9 views
55

Stavo usando affermazione "l'uscita 1" nelle mie funzioni di bash per terminare l'intero script e ha funzionato bene:C'è un modo per scrivere una funzione di bash che interrompe l'intera esecuzione, indipendentemente da come viene chiamata?

function func() 
{ 
    echo "Goodbye" 
    exit 1 
} 
echo "Function call will abort" 
func 
echo "This will never be printed" 

ma poi ho capito che non fa il lavoro quando viene chiamato come:

res=$(func) 

ho capito che ho creato una subshell e "l'uscita 1" interrompe che subshell e non quello primario ....

Ma c'è un modo di scrivere una funzione che interrompe tutta l'esecuzione, non importa com'è cal guidato? Ho solo bisogno di ottenere il valore di ritorno reale (echeggiato dalla funzione).

risposta

64

cosa si potrebbe fare, è il registro di shell di livello superiore per il segnale TERM per uscire, e quindi inviare un TERM alla shell di livello superiore:

#!/bin/bash 
trap "exit 1" TERM 
export TOP_PID=$$ 

function func() 
{ 
    echo "Goodbye" 
    kill -s TERM $TOP_PID 
} 

echo "Function call will abort" 
echo $(func) 
echo "This will never be printed" 

Quindi, la funzione invia un segnale TERM alla shell di livello superiore, che viene catturato e gestito utilizzando il comando fornito d, in questo caso, "exit 1".

+1

Stavo pensando alla funzione C' setsid() ', ma non funziona allo stesso modo. Aggiornato per non usare il comando 'setsid', in quanto richiederebbe l'avvio di un nuovo processo. – FatalError

+2

Funziona.Qualsiasi livello di nidificazione di funzioni, qualsiasi flusso ... Funziona solo. – LiMar

+0

È possibile creare una funzione abort generale() che esca dall'uso del codice del primo argomento, ad es. 'abort 2' farebbe il' trap 'exit 2 "TERM' prima di' kill'? –

26

È possibile utilizzare set -e che exits if a command exits with a non-zero status:

set -e 
func 
set +e 

O afferrare il valore di ritorno:

(func) || exit $? 
+1

È interessante notare una soluzione. "set -e" nello script principale fa in modo che qualsiasi funzione restituisca 1 (o che esca con esso) per interrompere l'intera esecuzione. Sfortunatamente "set -e" cambia drasticamente tutto il comportamento e non posso usarlo. – LiMar

+0

È necessario utilizzare (()) per confronti numerici. All'interno di [] -gt, -eq, ecc. Dovrebbe essere usato. – jordanm

+10

o anche 'res = $ (func) || exit' –

0

Un processo figlio non può forzare il processo padre di chiudere in modo implicito. Devi usare un qualche tipo di meccanismo di segnalazione. Opzioni potrebbe includere un valore speciale di ritorno, o forse l'invio di un segnale con kill, qualcosa come

function child() { 
    local parent_pid="$1" 
    local other="$2" 
    ... 
    if [[ $failed ]]; then 
     kill -QUIT "$parent_pid" 
    fi 
} 
0

Ma c'è un modo per scrivere una funzione che interrompe tutta l'esecuzione, non importa come si chiama?

No.

ho solo bisogno di ottenere il valore di ritorno reale (eco dalla funzione).

Puoi

res=$(func) 
echo $? 
Problemi correlati