pipeline bash d’arrêt d’urgence

J’ai un pipeline, disons un | b où si un problème se produit, je veux arrêter tout le pipeline.

‘une sortie avec exit = 1 ne le fait pas car souvent’ b ne se soucie pas des codes retour.

par exemple

echo 1 | grep 0 | echo $? <- cela montre que grep est sorti = 1 mais echo 1 | grep 0 | wc <— wc est pas perturbé par la sortie de grep ici

Si j’exécutais le pipeline en tant que sous-processus d’un processus propriétaire, tous les processus de pipeline pouvaient tuer le processus propriétaire. Mais cela semble un peu maladroit – mais cela va zapper tout le pipeline.

Pas possible avec des constructions shell de base, probablement pas possible en shell du tout.

Votre premier exemple ne fait pas ce que vous pensez. echo n’utilise pas d’entrée standard, le placer sur le côté droit d’un tuyau n’est donc jamais une bonne idée. Le $? que vous ne faites pas écho n’est pas la valeur de sortie du grep 0 . Toutes les commandes d’un pipeline s’exécutent simultanément. echo a déjà été lancé, avec la valeur existante de $? , avant que les autres commandes du pipeline soient terminées. Il fait écho à la valeur de sortie de ce que vous avez fait avant le pipeline.

 # The first command is to set things up so that $? is 2 when the # second command is parsed. $ sh -c 'exit 2' $ echo 1|grep 0|echo $? 2 

Votre deuxième exemple est un peu plus intéressant. Il est correct de dire que wc n’est pas perturbé par le statut de sortie de grep . Toutes les commandes du pipeline sont des enfants du shell, donc leurs états de sortie sont signalés au shell. Le processus wc ne sait rien du processus grep . La seule communication entre eux est le stream de données écrit dans le canal par grep et lu depuis le canal par wc .

Il y a moyen de trouver tous les états de sortie après le fait (la question liée dans le commentaire par shx2 a des exemples) mais une règle de base que vous ne pouvez pas éviter est que le shell attendra toujours que toutes les commandes se terminent.

Les premières sorties dans un pipeline ont parfois un effet en cascade. Si une commande sur le côté droit d’un tuyau se termine sans lire toutes les données du canal, la commande située à gauche de ce canal recevra un signal SIGPIPE sa prochaine tentative d’écriture, qui par défaut termine le processus. (Les deux phrases à surveiller sont “la prochaine fois qu’elle essaiera d’écrire” et “par défaut”. Si le processus d’écriture passe beaucoup de temps à faire d’autres choses entre les écritures sur le tube, il ne mourra pas immédiatement S’il gère le SIGPIPE, il ne mourra pas du tout.)

Dans l’autre sens, quand une commande sur le côté gauche d’un tuyau se ferme, la commande sur le côté droit de ce canal reçoit EOF, ce qui provoque la sortie assez rapidement quand il s’agit d’une commande simple comme wc qui ne fait pas beaucoup de traitement après la lecture de son entrée.

Avec l’utilisation directe de pipe() , fork() et wait3() , il serait possible de construire un pipeline, de savoir quand un enfant se ferme mal et de le tuer immédiatement. Cela nécessite un langage plus sophistiqué que le shell.

J’ai essayé de trouver un moyen de le faire en shell avec une série de canaux nommés, mais je ne le vois pas. Vous pouvez exécuter tous les processus en tant que travaux séparés et obtenir leurs PID avec $! , mais l’ wait interne n’est pas assez flexible pour dire “attendez qu’un enfant dans cet ensemble quitte, et dites-moi lequel il était et quel était le statut de sortie”.

Si vous êtes prêt à utiliser ps et / ou /proc vous pouvez trouver quels processus sont sortis (ils seront des zombies), mais vous ne pouvez pas distinguer une sortie réussie d’un autre type.

Écrire

 set -e set -o pipefail 

au début de votre fichier.

-e quittera une erreur et -o pipefail produira un code d’erreur à chaque étape de votre “pipeline”