Según su documentación, bash espera hasta que todos los comandos en una tubería hayan terminado de ejecutarse antes de continuar
El shell espera a que finalicen todos los comandos de la canalización antes de devolver un valor.
Entonces, ¿por qué el comando yes | truetermina de inmediato? ¿No debería el yesbucle para siempre y hacer que la tubería nunca regrese?
Y una pregunta secundaria: de acuerdo con la especificación POSIX , las tuberías de shell pueden elegir regresar después de que finalice el último comando o esperar hasta que finalicen todos los comandos. ¿Las conchas comunes tienen un comportamiento diferente en este sentido? ¿Hay algún caparazón donde yes | truese repita para siempre?

yes | tee >(true) >/dev/nullhará lo que espera, por cierto,teehasta que todos los escritores estén muertos, por lo quetruesalir no lo interrumpirá por completo.truees básicamente un{return 0;}programa, por lo que no esperaría que se ejecute por mucho tiempo, y mucho menos para siempre.Respuestas:
Cuando
truesale, el lado de lectura de la tubería está cerrado, peroyescontinúa intentando escribir en el lado de escritura. Esta condición se denomina "tubería rota" y hace que el núcleo envíe unaSIGPIPEseñalyes. Comoyesno hace nada especial con esta señal, será eliminada. Si ignoró la señal, eswritellamada fallará con el código de errorEPIPE. Los programas que hacen eso deben estar preparados para notarEPIPEy dejar de escribir, o entrarán en un ciclo infinito.Si lo haces
strace yes | true1 puedes ver el kernel preparándose para ambas posibilidades:straceestá viendo eventos a través de la API del depurador, que primero le informa sobre la devolución de la llamada del sistema con un error y luego sobre la señal. Sinyesembargo, desde la perspectiva, la señal ocurre primero. (Técnicamente, la señal se entrega después de que el núcleo devuelve el control al espacio del usuario, pero antes de que se ejecuten más instrucciones de la máquina, por lo que elwrite"wrapper" en la biblioteca C no tiene la oportunidad de establecererrnoy volver a la aplicación).1 Lamentablemente,
stracees específico de Linux. La mayoría de los Unix modernos tienen algún comando que hace algo similar, pero a menudo tiene un nombre diferente, probablemente no decodifique los argumentos de syscall tan a fondo, y a veces solo funciona para root.fuente
yesestá conectado a la tubería.yesobtener SIGPIPE, ya que el FD en el que está escribiendo no está conectado a una tubería.yes >/dev/nullse repite para siempre. No demuestra nada en absoluto sobre las tuberías que no son también ciertas para los comandos simples (como el comportamiento de espera de terminación que Tom señala también es cierto para los comandos simples).write()(la función en libc) no regresa (transfiere el control a la PC después de eso) hasta después el controlador de señal se ha ejecutado, pero como el controlador de señal finaliza el programa, el control nunca se transfiere y, por lo tanto,write()nunca regresa. Sí, eso se implementa en el núcleo al tener algunaxxx_write()función de retorno-EPIPE, pero estamos depurando un programa de espacio de usuario y sin interés en eso.Es poco probable, ya que el
yescomando está usando la tubería, y fallará cuando la tubería se rompa.sleeppor otro lado, no usa la tubería, entonces:correrá por 100000000 segundos, al menos.
fuente
trueestá un incorporado. Esto se aplica a las versiones recientes delBourne Shell,ksh93,zsh. Si presiona^Zcuando se ejecuta un comando de este tipo, se suspenderá la suspensión y el shell nunca podrá recuperarse sin ayuda externa.sbrk(). Una versión portátil y mantenida está en el paquete de herramientas schily y @Charles Duffy ya descubrió una ubicación para obtener información ;-)bsh(Berthold Shell de VBERTOS, una versión mejorada de memoria virtual de UNOS - el primer clon de UNIX). Bsh obtuvo muchas características de csh en 1984 y 1985, pero el mecanismo de alias de UNOS ya era superior al de csh en 1980. Otras características nuevas de Bourne Shell son de POSIX, para permitir que se acerque al cumplimiento de POSIX.