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.