[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Cleanup in a bash script



On Wed, Oct 02, 2024 at 13:59:04 +0200, tomas@tuxteam.de 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.


Reply to: