On Wed, Oct 02, 2024 at 13:59:04 +0200, [email protected] wrote: > On Wed, Oct 02, 2024 at 02:43:11PM +0300, Anssi Saari wrote: > > Running ./script |& tee -i log works as expected. The script gets the > > INT signal and cleans up. > > Understood. > > > To me, "signal passing up the pipe" is an apt analogy of how things work > > in practice. > > This triggered the wrong association for me, TBH :) > > What actually happens seems completely different to me: the shell > gets the EPIPE from the dying tee before it can see the EINTR, right?
Let's assume one opens a terminal with an interactive shell running inside it, and then types the command "./script |& tee -i log", and then presses Ctrl-C. In that case, there are THREE foreground processes which receive a SIGINT: * The interactive shell, which ignores it, because interactive shells always ignore SIGINT. * The ./script process, which is presumably expanded to "/bin/bash ./script". * The tee -i log process. We know the interactive shell ignores it, and we can reasonably assume that the tee will accept it and terminate. So then the question becomes what the /bin/bash ./script process will do with it. If the tee process terminates, bash won't *know* that it's gone until it tries to write to the pipeline. When it tries to write to a broken pipeline, it will receive a SIGPIPE. If it never writes to the broken pipeline, it will never know the tee is dead. If the script is NOT actively writing to the pipeline at the time Ctrl-C is pressed, but has a trap set up which tries to write to the pipeline upon receiving SIGINT, then there's a race condition between the shell's trap activating and trying to write to the pipeline, and the tee process trying to close the pipeline. I'm guessing tee wins that race most of the time. The differing behavior between the builtin echo command, and an external /bin/echo command, when writing to a broken pipe in an EXIT trap, is news to me, honestly. I've never run into it myself. What I'm mostly trying to convey here, though, is that signals do not *propagate* from one process to another in any kind of automatic way. It doesn't matter whether the two processes are connected by a pipe, or are parent/child to each other, or anything else. Killing a parent process does not automatically kill the child. Killing one process in a pipeline does not automatically kill any other process in the pipeline. And finally, pressing Ctrl-C in a terminal sends MANY signals, and therefore is immensely different from sending a SIGINT to just one process.

