2015-04-29 13 views
5

Io uso set -e all'interno di (...) sulla riga di comando ma non esce dalla sottoshell quando viene eseguito il comando false.Subshell creato usando (...) si comporta diversamente da bash -c '...'

Codice 1:

(set -e; echo "$BASHPID: start"; false; echo "foobar"; date;) && 
    echo "$BASHPID: ok" || echo "$BASHPID: nope" 
9136: start 
foobar 
Wed, Apr 29, 2015 7:14:24 PM 
7292: ok 

Tuttavia se uso bash -c per la creazione di subshell poi si comporta come mi aspetto.

Codice 2:

bash -c 'set -e; echo "$BASHPID: start"; false; echo "foobar"; date;' && 
    echo "$BASHPID: ok" || echo "$BASHPID: nope" 
7880: start 
7292: nope 

È interessante notare che se tolgo && e || parte dopo subshell poi (...) comporta anche bene.

Codice 3:

(set -e; echo "$BASHPID: start"; false; echo "foobar"; date;) 
5940: start 

Così conclusioni che sto ottenendo sono:

  1. (...) si comporta in modo diverso da bash -c
  2. (...) && false si comporta in modo diverso da (...) e cambia il comportamento di subshell pure.

Sto facendo un errore evidente nell'interpretare questo comportamento strano (almeno per me)?

+4

Il comportamento di 'set -e' con' && 'è intenzionale. Non si attiva esplicitamente quando il comando fa parte di una sequenza '&&'. Questo è nel manuale. Presumo che la differenza qui sia se la shell conosce questo fatto. '(...)' presumibilmente fa perché la shell corrente la esegue e 'bash -c' presumibilmente no perché è un processo completamente esterno (o qualcosa del genere). –

+0

Ah, vedo che '&&' fa la differenza solo per sottoshell creato usando '(...)' ma non per le sotto shell create usando 'bash -c', interessante. Ho imparato qualcosa di nuovo. – anubhava

+0

@EtanReisner: Credo che dovresti convertire il tuo commento in una risposta. – anubhava

risposta

2

Il comportamento di set -e con && è intenzionale.

Non si attiva esplicitamente quando il comando fa parte di una sequenza &&.

Dalla specifiche POSIX:

-e

Quando questa opzione è attiva, quando un comando non riesce (per qualsiasi delle ragioni elencate nelle conseguenze di errori Shell o restituendo un'uscita stato maggiore di zero), la shell deve uscire immediatamente con le seguenti eccezioni: L'errore di qualsiasi singolo comando in una pipeline a più comandi non deve causare l'uscita della shell. Sarà considerato solo il guasto della condotta stessa.

L'impostazione -e deve essere ignorata quando si esegue l'elenco composto dopo un istante, fino a quando, se, o parola riservata elif, una pipeline che inizia con! parola riservata, o qualsiasi comando di una lista AND-OR diversa dall'ultima.

Se lo stato di uscita di un comando composto diverso da un comando di subshell era il risultato di un errore mentre -e veniva ignorato, allora -e non si applica a questo comando.

Questo requisito si applica all'ambiente di shell e ad ogni ambiente di subshell separatamente.Ad esempio, in:

set -e; (false; echo one) | cat; echo two 

il comando falso causa l'uscita della sottoshell senza eseguire echo uno; tuttavia, echo due viene eseguito perché lo stato di uscita della pipeline (false; echo uno) | il gatto è zero.

Suppongo che la differenza qui sia se la shell conosce questo fatto.

(...) presumibilmente fa perché lo shell corrente lo esegue e bash -c presumibilmente non perché è un processo completamente esterno (o qualcosa).

L'ultimo bit è la speculazione e, a mio parere, il comportamento del sub-shell qui è del tutto inutile e rende inaffidabile set -e (motivo per cui molte persone suggeriscono di evitarlo).

Anche se sembra che questo potrebbe anche fornire una sorta di "escape hatch" per quel problema di affidabilità se una shell eseguita in modo esplicito non ha quel problema con la composizione degli script.

Problemi correlati