Impostazione pipefail per un singolo comando con pipe


18

Ho bisogno di eseguire un numero di comandi shell convogliati da uno script non BASH (vale a dire script PHP) come questi:

command1 | command2 | command3

in modo che, se command1fallisce con un codice di uscita diverso da zero, anche l'altro comando fallisce. Finora, quello che ho escogitato è:

set -o pipefail && command1 | command2 | command3

Ma anche se funziona bene dal terminale, produce questo se eseguito dallo script:

sh: 1: set: opzione illegale -o pipefail


Sembra che /bin/shnon mi piace set -o pipefail. In realtà è bashsotto mentite spoglie o è un guscio diverso? Quando bashviene eseguito come /bin/sh, accetta set -o pipefail?
Jonathan Leffler,

@JonathanLeffler Quando corro /bin/sh set -o pipefaildice /bin/sh: 0: Can't open set(stessa cosa con sudo). Spero di averlo provato bene. Il sistema è Ubuntu 12.
Desmond Hume

Dovresti provare /bin/sh -c "set -o pipefail"; com'era, la shell stava cercando di eseguire uno script nella directory corrente chiamata sete non l'ha trovata.
Jonathan Leffler,

@JonathanLeffler /bin/sh -c "set -o pipefail"non funziona, tuttavia bash -c "set -o pipefail"funziona.
Desmond Hume,

Quindi, il tuo problema è che lo script viene eseguito e /bin/shche non riconosce set -o pipefail. Di conseguenza, dovrai assicurarti che lo script sia eseguito al /bin/bashposto di /bin/sh. Oppure, se sei sicuro, coraggioso - e probabilmente insensato - cambia /bin/shper essere un link o una copia di, /bin/bashinvece di qualunque shell a cui è attualmente collegato o una copia di. Se sei sicuro che lo /bin/shsia bash, allora stai usando un comportamento che bashnon espone quando eseguito come /bin/sh; usa bashcome bash.
Jonathan Leffler,

Risposte:


18

Dalla riga di comando di Bash dovresti invocare una subshell per evitare di pipefailessere impostata in seguito:

$ (set -o pipefail && command1 | command2 | command3)

Ciò limiterebbe l'effetto pipefaildell'opzione alla sottostruttura creata dalle parentesi (...).

Un vero esempio:

$ (set -o pipefail && false | true) && echo pipefail inactive || echo pipefail active
pipefail active

Se si utilizza una chiamata shell esplicita con l' -copzione non è necessaria una subshell, con basho con un shalias per bash:

$ bash -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active
$ sh -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active

Dal momento che il tuo shnon accetta l' pipefailopzione, dovrei presumere che sia una versione precedente o modificata di bash- o che in realtà sia completamente un'altra shell.


1
È $nel primo pezzo di una parte del comando è solo una shell? Ho provato in entrambi i modi, non ha funzionato davvero. Il bash -cmodo in cui funziona sempre, non troppo elegante ...
Desmond Hume,

5

Non sono sicuro del motivo per cui non è stato menzionato sopra, ma è possibile annullare esplicitamente pipefail, utilizzando set +o pipefail.

set -o pipefail
command1 | command2 | command3
set +o pipefail

Se stai eseguendo un frammento e non pipefailsei sicuro del già impostato, puoi usarlo con la subshell come suggerito in precedenza:

# explicitly execute with pipefail set
(set -o pipefail ; command1 | command2 | command3 )
# explicitly execute with pipefail unset
(set +o pipefail ; command1 | command2 | command3 )

0

Puoi usare $ (command1) combinato con $? :

a=$(echo "a")
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

Stampa "abc"

a=$(ls unexitingDir)
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

Stampa "".

"[$? -eq 0] &&" indica che il comando seguente viene eseguito solo se il precedente ha avuto esito positivo.

Questo non risponde alla tua domanda ma è una soluzione al tuo problema.


Vuol dire che avrei sempre bisogno di memorizzare l'output di ciascuno dei comandi in una variabile?
Desmond Hume,

Sempre non lo so, ma con la mia soluzione sì lo farai (se ne hai bisogno per il tuo prossimo comando). A meno che tu non possa semplicemente scriverecommand1 && command2 && command3
cglacet il
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.