Si vous ne voulez vraiment pas que la deuxième commande se poursuive jusqu'à ce que la première soit réussie, vous devez probablement utiliser des fichiers temporaires. La version simple de cela est:
tmp=${TMPDIR:-/tmp}/mine.$$
if ./a > $tmp.1
then
if ./b <$tmp.1 >$tmp.2
then
if ./c <$tmp.2
then : OK
else echo "./c failed" 1>&2
fi
else echo "./b failed" 1>&2
fi
else echo "./a failed" 1>&2
fi
rm -f $tmp.[12]
La redirection «1> & 2» peut également être abrégée «> & 2»; cependant, une ancienne version du shell MKS a mal géré la redirection d'erreur sans le «1» précédent, j'ai donc utilisé cette notation sans ambiguïté pour la fiabilité depuis des lustres.
Cela fuit des fichiers si vous interrompez quelque chose. La programmation shell à l'épreuve des bombes (plus ou moins) utilise:
tmp=${TMPDIR:-/tmp}/mine.$$
trap 'rm -f $tmp.[12]; exit 1' 0 1 2 3 13 15
...if statement as before...
rm -f $tmp.[12]
trap 0 1 2 3 13 15
La première ligne de déroutement dit `` exécuter les commandes ' rm -f $tmp.[12]; exit 1
' quand l'un des signaux 1 SIGHUP, 2 SIGINT, 3 SIGQUIT, 13 SIGPIPE ou 15 SIGTERM se produit, ou 0 (lorsque le shell sort pour une raison quelconque). Si vous écrivez un script shell, le trap final n'a besoin que de supprimer le trap sur 0, qui est le trap de sortie du shell (vous pouvez laisser les autres signaux en place puisque le processus est sur le point de se terminer de toute façon).
Dans le pipeline d'origine, il est possible que «c» lise les données de «b» avant que «a» ne soit terminé - c'est généralement souhaitable (cela donne du travail à plusieurs cœurs, par exemple). Si 'b' est une phase de 'tri', alors cela ne s'appliquera pas - 'b' doit voir toutes ses entrées avant de pouvoir générer l'une de ses sorties.
Si vous souhaitez détecter les commandes qui échouent, vous pouvez utiliser:
(./a || echo "./a exited with $?" 1>&2) |
(./b || echo "./b exited with $?" 1>&2) |
(./c || echo "./c exited with $?" 1>&2)
C'est simple et symétrique - il est trivial de s'étendre à un pipeline en 4 parties ou en N parties.
Une simple expérimentation avec 'set -e' n'a pas aidé.
&&|
qui signifierait "ne continuer le tube que si la commande précédente a réussi". Je suppose que vous pourriez aussi avoir|||
ce qui signifierait "continuer le tube si la commande précédente a échoué" (et éventuellement envoyer le message d'erreur comme celui de Bash 4|&
).