Définition de pipefail pour une seule commande canalisée


18

J'ai besoin d'exécuter un certain nombre de commandes shell canalisées à partir d'un script non BASH (à savoir un script PHP) comme ceux-ci:

command1 | command2 | command3

de sorte qu'en cas d' command1échec avec un code de sortie différent de zéro, chaque autre commande échoue également. Jusqu'à présent, ce que j'ai trouvé est:

set -o pipefail && command1 | command2 | command3

Mais même s'il fonctionne correctement depuis le terminal, il produit ceci s'il est exécuté à partir du script:

sh: 1: set: option illégale -o pipefail


Il semble que ça /bin/shn'aime pas set -o pipefail. Est-ce en fait bashdéguisé ou s'agit-il d'une coquille différente? Quand bashest-il exécuté comme /bin/sh, accepte- set -o pipefailt- il ?
— Jonathan Leffler

@JonathanLeffler Quand je cours, /bin/sh set -o pipefailil dit /bin/sh: 0: Can't open set(même chose avec sudo). J'espère que je l'ai testé correctement. Le système est Ubuntu 12.
— Desmond Hume

Vous auriez besoin d'essayer /bin/sh -c "set -o pipefail"; tel qu'il était, le shell essayait d'exécuter un script dans le répertoire courant appelé setet il ne l'a pas trouvé.
— Jonathan Leffler

@JonathanLeffler /bin/sh -c "set -o pipefail"ne fonctionne pas, cependant bash -c "set -o pipefail".
— Desmond Hume

Donc, votre problème est que le script est exécuté par /bin/shqui ne reconnaît pas set -o pipefail. Par conséquent, vous devrez vous assurer que le script est exécuté par /bin/bashau lieu de /bin/sh. Ou, si vous êtes confiant, courageux - et probablement imprudent - changez /bin/shpour être un lien ou une copie de, /bin/bashau lieu du shell auquel il est actuellement lié ou d'une copie. Si vous êtes sûr que /bin/shest bash, alors vous utilisez un comportement qui bashn'expose pas lorsqu'il est exécuté comme /bin/sh; utiliser bashcomme bash.
— Jonathan Leffler

Réponses:


18

À partir de la ligne de commande Bash, vous devrez appeler un sous-shell pour éviter d' pipefailêtre défini par la suite:

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

Cela limiterait l'effet de l' pipefailoption au sous-shell créé par les parenthèses (...).

Un vrai exemple:

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

Si vous utilisez un appel shell explicite avec l' -coption, vous n'avez pas besoin d'un sous-shell, avec bashou avec un shalias pour 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

Puisque votre shn'accepte pas l' pipefailoption, je devrais supposer qu'il s'agit d'une version plus ancienne ou modifiée de bash- ou qu'il s'agit en fait d'un autre shell complètement.


1
Est-ce que $dans la première partie une partie de la commande est-ce juste une invite shell? Essayé dans les deux sens, n'a pas vraiment fonctionné. La bash -cmanière fonctionne toujours, pas trop élégante cependant.
— Desmond Hume

5

Je ne sais pas pourquoi cela n'a pas été mentionné ci-dessus, mais il est possible de désactiver explicitement l' pipefailutilisation set +o pipefail.

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

Si vous exécutez un fragment et n'êtes pas sûr de ce qui est pipefaildéjà défini, vous pouvez l'utiliser avec le sous-shell comme suggéré précédemment:

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

0

Vous pouvez utiliser $ (command1) combiné avec $? :

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

Imprime "abc"

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

Imprime "".

"[$? -eq 0] &&" signifie que la commande suivante n'est exécutée que si la précédente a réussi.

Cela ne répond pas à votre question mais c'est une solution à votre problème.


Cela signifie-t-il que j'aurais toujours besoin de stocker la sortie de chacune des commandes dans une variable?
— Desmond Hume

Toujours je ne sais pas mais avec ma solution oui vous le ferez (si vous en avez besoin pour votre prochaine commande). Sauf si vous pouvez simplement écrirecommand1 && command2 && command3
— cglacet
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.