Reputation: 2058
My sample file
traptest.sh:
#!/bin/bash
trap 'echo trapped' TERM
while :
do
sleep 1000
done
$ traptest.sh &
[1] 4280
$ kill %1 <-- kill by job number works
Terminated
trapped
$ traptest.sh &
[1] 4280
$ kill 4280 <-- kill by process id doesn't work?
(sound of crickets, process isn't killed)
If I remove the trap statement completely, kill process-id works again?
Running some RHEL 2.6.18-194.11.4.el5 at work. I am really confused by this behaviour, is it right?
Upvotes: 16
Views: 27905
Reputation: 675
Davide Berra explained the difference between kill %<jobspec>
and kill <PID>
, but not how that difference results in what you observed. After all, Unix signal handlers should be called pretty much instantaneously, so why does sending a SIGTERM
to the script alone not trigger its trap handler?
The bash
man page explains why, in the last paragraph of the SIGNALS section:
If
bash
is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes.
So, the signal was delivered immediately, but the handler execution was deferred until sleep
exited.
Hence, with kill %<jobspec>
:
sleep
received SIGTERM
bash
registered the signal, noticed that a trap
was set for it, and queued the handler for future executionsleep
exited immediatelybash
noted sleep
's exit, and ran the trap handlerwhereas with kill <script_PID>
:
SIGTERM
bash
registered the signal, noticed that a trap
was set for it, and queued the handler for future executionsleep
exited after 1000 secondsbash
noted sleep
's exit, and ran the trap handlerObviously, you didn't want long enough to see that last bit. :)
If you're interested in the gory details, download the bash
source code and look in trap.c
, specifically the trap_handler()
and run_pending_traps()
functions.
Upvotes: 6
Reputation: 6568
kill [pid]
send the TERM signal exclusively to the specified PID.
kill %1
send the TERM signal to the job #1's entire process group, in this case to the script pid + his children (sleep).
I've verified that with strace on sleep process and on script process
Anyway, someone got a similar problem here (but with SIGINT instead of SIGTERM): http://www.vidarholen.net/contents/blog/?p=34.
Quoting the most important sentence:
kill -INT %1 sends the signal to the job’s process group, not the backgrounded pid!
Upvotes: 12
Reputation: 313
This is expected behavior. Default signal sent by kill
is SIGTERM
, which you are catching by your trap. Consider this:
#!/bin/bash
# traptest.sh
trap "echo Booh!" SIGINT SIGTERM
echo "pid is $$"
while : # This is the same as "while true".
do
a=1
done
(sleep really creates a new process and the behavior is clearer with my example I guess).
So if you run traptest.sh
in one terminal and kill TRAPTEST_PROCESS_ID
from another terminal, output in the terminal running traptest will be Booh!
as expected (and the process will NOT be killed). If you try sending kill -s HUP TRAPTEST_PROCESS_ID
, it will kill the traptest process.
This should clear up the %1
confusion.
Note: the code example is taken from tldp
Upvotes: 8