Tengo una canalización, digamos a|b donde si a se encuentra con un problema, quiero detener toda la canalización.
'a salir con exit=1 no hace esto tan a menudo 'b no se preocupa por los códigos de retorno.
p.ej
eco 1|grep 0|echo $? <-- esto muestra que grep salió = 1 pero echo 1|grep 0 | wc <--- wc no se inmuta por la salida de grep aquí
Si ejecuto la tubería como un subproceso de un proceso propietario, cualquiera de los procesos de la tubería podría eliminar el proceso propietario. Pero esto parece un poco torpe, pero eliminaría toda la tubería.
No es posible con construcciones básicas de shell, probablemente no sea posible en shell en absoluto.
Tu primer ejemplo no hace lo que piensas. echo no usa entrada estándar, por lo que ponerlo en el lado derecho de una tubería nunca es una buena idea. El $? que estás haciendo eco no es el valor de salida de grep 0 . Todos los comandos en una canalización se ejecutan simultáneamente. echo ya se ha iniciado, con el valor existente de $? , antes de que finalicen los demás comandos de la canalización. Hace eco del valor de salida de lo que haya hecho antes de la canalización.
# 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 Su segundo ejemplo es un poco más interesante. Es correcto decir que wc no se inmuta por el estado de salida de grep . Todos los comandos en la canalización son elementos secundarios del shell, por lo que sus estados de salida se informan al shell. El proceso wc no sabe nada sobre el proceso grep . La única comunicación entre ellos es el flujo de datos escrito en la tubería por grep y leído desde la tubería por wc .
Hay formas de encontrar todos los estados de salida después del hecho (la pregunta vinculada en el comentario de shx2 tiene ejemplos), pero una regla básica que no puede evitar es que el shell siempre esperará a que finalicen todos los comandos.
Las salidas tempranas en una tubería a veces tienen un efecto de cascada. Si un comando en el lado derecho de una tubería sale sin leer todos los datos de la tubería, el comando a la izquierda de esa tubería obtendrá una señal SIGPIPE la próxima vez que intente escribir, lo que por defecto finaliza el proceso. (Las 2 frases a las que hay que prestar mucha atención son "la próxima vez que intente escribir" y "por defecto". Si el proceso de escritura pasa mucho tiempo haciendo otras cosas entre escrituras en la canalización, no morirá inmediatamente. Si maneja el SIGPIPE, no morirá en absoluto.)
En la otra dirección, cuando sale un comando en el lado izquierdo de una tubería, el comando en el lado derecho de esa tubería obtiene EOF, lo que hace que la salida ocurra bastante pronto cuando es un comando simple como wc que no funciona. mucho procesamiento después de leer su entrada.
Con el uso directo de pipe() , fork() y wait3() , sería posible construir una tubería, notar cuando un niño sale mal y matar al resto de ellos inmediatamente. Esto requiere un lenguaje más sofisticado que el shell.
Traté de encontrar una forma de hacerlo en shell con una serie de canalizaciones con nombre, pero no lo veo. ¡Puede ejecutar todos los procesos como trabajos separados y obtener sus PID con $! , pero la wait incorporada no es lo suficientemente flexible como para decir "espere a que salga cualquier niño en este conjunto y dígame cuál fue y cuál fue el estado de salida".
Si está dispuesto a meterse con ps y/o /proc , puede averiguar qué procesos han salido (serán zombis), pero no puede distinguir la salida exitosa de ningún otro tipo.
Escribe
set -e set -o pipefailal principio de su archivo.
-e saldrá con un error y -o pipefail producirá un código de error en cada etapa de su "tubería"