2013-02-20 7 views
11

Sono un po 'confuso qui. Il mio obiettivo qui è di far uscire lo script di bash con un codice di uscita diverso da zero quando uno dei comandi all'interno dello script fallisce. Usando il flag -e, ho pensato che sarebbe stato il caso, anche quando si usavano le subshell. Di seguito è riportato un esempio semplificato:Perché bash flag -e esce quando una subshell fallisce?

#!/bin/bash -e 

(false) 

echo $? 
echo "Line reached!" 

Qui è l'uscita quando correva:

[$]>Tests/Exec/continuous-integration.sh 
1 
Line reached! 

versione Bash: 3.2.25 su CentOS

+0

C'è qualche possibilità di tutto ciò che è possibile aggiornare la tua versione bash, perché questo script esatto funziona come previsto in 4.1.5. Forse è la tua versione 'false' –

risposta

8

Sembra come se questo è legato alla versione di bash. Su macchine alle quali ho accesso, bash versione 3.1.17 e 3.2.39 mostrano questo comportamento, bash 4.1.5 no.

Anche se un po 'brutto, una soluzione che funziona in entrambe le versioni potrebbe essere qualcosa di simile:

#!/bin/bash -e 

(false) || exit $? 

echo $? 
echo "Line reached!" 

Ci sono alcune note nel changelog fonte bash che riguardava bug con l'opzione set -e.

+0

Ah, grazie per lo scavo, è stato questo! Grazie per la risposta suggerita, è esattamente quello che farò. –

+1

Non so quale OP OS è attivo, ma ad es. Il leone di montagna viene ancora spedito con bash 3, sfortunatamente. –

0

Ho visto questo comportamento in bash versione 3.2.51 su SuSE 11.3 e Mac OS precedente a El Capitan. Bash 3.2.57 su El Capitan ha il comportamento "corretto", ad esempio bash 4.

Tuttavia, la soluzione proposta sopra, aggiungendo "|| exit $?" dopo il paren di chiusura della sottoshell, sconfigge l'intento della bandiera -e indipendentemente dalla versione di bash. Da man bash:

Exit -e immediatamente se un comando semplice (si veda GRAMMATICA DELLA SHELL sopra) termina con uno stato diverso da zero. La shell non esce se il comando che fallisce è parte dell'elenco comandi immediatamente dopo un po 'o fino alla parola chiave, parte del test in un'istruzione if, parte di uno & & o || lista, ...

Una sottoshell seguita da "|| exit $?" apparentemente conta come una lista di comandi; e il flag bash -e non si applica a QUALSIASI comando all'interno della sottoshell. Provalo:

$ set -e 
$ (echo before the error; false; echo after the error, status $?;) || echo after the subshell, status $? 
before the error 
after the error, status 1 
$ 

Perché la subshell è seguito da ||, che "eco dopo l'errore" viene eseguito, anche con set -e. Non solo, la subshell esce da 0, perché "echo" ha funzionato. Quindi "|| exit $?" non avrebbe nemmeno eseguito "l'uscita". Probabilmente non quello che volevamo!

Per quanto ne so, la seguente formula è compatibile con le versioni bash sia che rispettino bash -e dopo subshell, oppure no. Si comporta anche correttamente se il flag -e sembra essere resettare:

Aggiungere la seguente riga immediatamente dopo la parentesi di chiusura di ogni subshell nello script bash:

case $?/$- in (0/*) ;; (*/*e*) exit $? ;; esaC# honor bash -e flag when subshell returns 
Problemi correlati