
Para ser claro con la pregunta del título, entiendo por qué muere el primero. No entiendo por qué este último no lo hace, solo por agregar un | cat
al cuerpo del bucle.
También tal vez relacionado,
while true; do echo y; done
muere inmediatamente cuando lo hago ^C
, pero matando
while true; do echo y | cat; done
A menudo es necesario golpearlo ^C
más de una vez. A veces funciona una vez, otras veces funciona 2 o 3 veces, luego hay momentos en los que necesito aguantar ^C
un rato para que muera.
Ambos comportamientos ocurren tanto en bash como en zsh, aunque ^C
uno parece ser más raro con bash.
Para ambos comportamientos, esto no se limita a agregar la tubería a cat
. | dd
, | tee
, etc. también los causan. Incluso echo y | true
lo provoca. Parece ser la presencia de algún tubo en el cuerpo del bucle.
¿Por qué la presencia de una tubería en el cuerpo de un bucle cambia la respuesta del bucle a las señales?
Respuesta1
En while true; do echo y; done | true
, como echo
está integrado, tienes un proceso de subcapa que escribe y\n
en un bucle en una tubería.
Cuando true
regresa, el extremo de lectura de esa tubería se cierra, por lo que escribir en el extremo de escritura hace que se SIGPIPE
entregue a al proceso de escritura. Aquí, ese es el proceso de subcapa que ejecuta el ciclo.
En while true; do echo y | cat; done | true
, es cat
el que escribe en la tubería. cat
generalmente no está integrado, e incluso si lo estuviera, en shells distintos de zsh y ksh, todos los componentes de tuberías siempre se ejecutan en procesos secundarios.
Entonces, aquí solo el proceso en ejecución cat
muere y el proceso de subcapa que ejecuta el bucle continúa ejecutando más cat
procesos que mueren tan pronto como escriben y\n
en su salida estándar.
En ksh93/ksh2020, si lo hace:
$ builtin cat
$ type cat
cat is a shell builtin
$ set -o pipefail
$ while true; do echo y | cat; done | true; kill -l "$?"
PIPE
Esta vez, cat
está integrado y se ejecuta en el mismo proceso que el bucle (al igual que cat
el comando más a la derecha en la primera línea de canalización y ksh no lo ejecuta en un subshell), por lo que el subshell sale true
y kill -l
confirma que fue asesinado por un SIGPIPE.