I’ve got the following script:
#!/bin/bash echo "We are $$" trap "echo HUP" SIGHUP cat # wait indefinitely
When I send SIGHUP (using kill -HUP pid), nothing happens.
If I change the script slightly:
#!/bin/bash echo "We are $$" trap "kill -- -$BASHPID" EXIT # add this trap "echo HUP" SIGHUP cat # wait indefinitely
…then the script does the echo HUP thing right as it exits (when I press Ctrl+C):
<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cfbda0a8aabd8fbda0a8aabde2bfac">[email protected]</a>:~ $ ./hupper.sh We are 6233 ^CHUP
What’s going on? How should I send a signal (it doesn’t necessarily have to be SIGHUP) to this script?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
The Bash manual states:
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.
That means that despite the signal is received by bash when you send it, your trap on SIGHUP will be called only when cat ends.
If this behavior is undesirable, then either use bash builtins (e.g. read + printf in a loop instead of cat) or use background jobs (see Stéphane’s answer).
Method 2
@xhienne has already explained why, but if you wanted to have the signal acted on straight away (and not exit the script), you could change your code to:
#! /bin/bash -
interrupted=true
trap 'interrupted=true; echo HUP' HUP
{ cat <&3 3<&- & pid=$!; } 3<&0
while
wait "$pid"
ret=$?
"$interrupted"
do
interrupted=false
done
exit "$ret"
The little dance with file descriptors is to work around the fact that bash redirects stdin to /dev/null for commands launched in background.
Method 3
I have noticed that when you have a trap on EXIT, the script does not wait for an external command to end when it receives a signal. Example script:
$ cat test-trap #!/bin/bash echo "We are $$" trap "echo 'Trapping EXIT'" EXIT cat
Running it:
$ ./test-trap We are 24814
Sending it a SIGHUP:
$ ./test-trap We are 24814 # Doing `kill -HUP 24814` in another terminal Trapping EXIT Hangup
There may be a confused abandoned cat though:
cat: -: Input/output error
To solve this, you may want to search and kill child processes from a function called by the trap.
Pressing Ctrl+C:
$ ./test-trap We are 24814 ^CTrapping EXIT
Now, when you press Ctrl+D instead of Ctrl+C, the cat command ends normally. But then the trap is executed when the script ends:
$ ./test-trap We are 40183 # I pressed Ctrl+D here... Trapping EXIT
You can prevent that by unsetting the trap at the end of the script:
#!/bin/bash echo "We are $$" trap "echo 'Trapping EXIT'" EXIT cat trap - EXIT
I was unable to find any documentation for this different behaviour of trapping EXIT. Perhaps someone else can?
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0