Si realmente no desea que el segundo comando continúe hasta que se sepa que el primero es exitoso, entonces probablemente necesite usar archivos temporales. La versión simple de eso es:
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 redirección '1> & 2' también se puede abreviar '> & 2'; sin embargo, una versión anterior del shell MKS manejó mal la redirección de errores sin el '1' anterior, por lo que he usado esa notación inequívoca para la confiabilidad durante años.
Esto filtra archivos si interrumpe algo. Usos de programación de shell a prueba de bombas (más o menos):
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 primera línea de trampa dice 'ejecutar los comandos' rm -f $tmp.[12]; exit 1
'cuando ocurre alguna de las señales 1 SIGHUP, 2 SIGINT, 3 SIGQUIT, 13 SIGPIPE o 15 SIGTERM, o 0 (cuando el shell sale por cualquier motivo). Si está escribiendo un script de shell, la trampa final solo necesita eliminar la trampa en 0, que es la trampa de salida de shell (puede dejar las otras señales en su lugar ya que el proceso está a punto de terminar de todos modos).
En la canalización original, es factible que 'c' lea datos de 'b' antes de que 'a' haya terminado; esto suele ser deseable (por ejemplo, da trabajo a varios núcleos). Si 'b' es una fase de 'clasificación', entonces esto no se aplicará; 'b' tiene que ver todas sus entradas antes de poder generar cualquiera de sus salidas.
Si desea detectar qué comando (s) fallan, puede usar:
(./a || echo "./a exited with $?" 1>&2) |
(./b || echo "./b exited with $?" 1>&2) |
(./c || echo "./c exited with $?" 1>&2)
Esto es simple y simétrico: es trivial extenderlo a una tubería de 4 o N partes.
La simple experimentación con 'set -e' no ayudó.
&&|
lo que significaría "solo continuar con la tubería si el comando anterior fue exitoso". Supongo que también podría haberlo hecho,|||
lo que significaría "continuar la tubería si el comando anterior falló" (y posiblemente enviar el mensaje de error como Bash 4|&
).