[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: looking for consistent C-c trap behavior
From: |
Greg Wooledge |
Subject: |
Re: looking for consistent C-c trap behavior |
Date: |
Fri, 17 Apr 2020 16:09:16 -0400 |
User-agent: |
Mutt/1.10.1 (2018-07-13) |
On Fri, Apr 17, 2020 at 01:02:20PM -0700, Eduardo Bustamante wrote:
> On Fri, Apr 17, 2020 at 12:59 PM gentoo_eshoes--- via Bug reports for
> the GNU Bourne Again SHell <bug-bash@gnu.org> wrote:
> >
> > I've noticed that if I trap SIGINT in a bash script, the behavior when
> > encountering C-c depends on whether an external command (eg. 'sleep 100')
> > or a builtin command (like 'read -p') was encountered.
> >
> > I attach an example script which requires me to press C-c twice to
> > interrupt the builtin 'read -p' command, and it only works because I'm
> > restoring the trap via 'trap - SIGINT' the first time.
> >
> > My goal is to have C-c interrupt and use that exit code (130 most likely)
> > to exit with from script, regardless or whether or not the interrupted
> > command in the script was an internal or external one.
> >
> > How to do?
>
> I recommend reading: https://www.cons.org/cracauer/sigint.html
>
> The problem is that the signal is sent to the foreground process. When
> "sleep" is running, it's the sleep command that receives the signal
> and decides what to do with it. Not bash.
That's not quite right. When you press ^C in a terminal, SIGINT is sent
to *all* of the processes in the "foreground" process group -- both sleep
and bash, in the case you're discussing.
The URL you linked to describes the behavior of bash when one of its
child processes exits in a way consistent with death by SIGINT. This
doesn't change the fact that bash itself *does* get the signal.
The easiest way to trigger the kind of situations the cons.org page is
talking about is to use an interactive shell, where SIGINT is ignored
by bash, and a command that traps SIGINT in the "incorrect" way. A
perfect example of this is ping.
while true; do
ping 127.0.0.1
done
It's VERY hard to kill this loop, because each time you hit ^C, ping
will be killed, but it traps SIGINT and exits by itself, so bash
assumes that the SIGINT was used in a non-terminal way, and doesn't
exit the loop.
Compare to:
while true; do
sleep 10
done
Terminating this loop is simple: press ^C once, and sleep is killed by
SIGINT, and bash detects this, and stops the loop.