10

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):

roger@roger-pc:~ $ ./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?

  • 4
    The signal will be delivered and the signal handler will execute when the cat process finishes. Try your original script and press Ctrl+D to make the cat process exit. While the cat process is in the foreground, the HUP signal is not acted upon. Try again with cat replaced by read (a shell built-in). – Kusalananda Aug 23 '17 at 9:59
  • Perfect. Does someone fancy turning that into an answer? – Roger Lipscombe Aug 23 '17 at 10:03
  • I know it works that way, but I'll let someone who have more insight than me into the whys and wherefores do the answer. – Kusalananda Aug 23 '17 at 10:04
  • I used while true; do read; done in the end, otherwise entering text causes it to quit as well, and I want it to quit on Ctrl+C. – Roger Lipscombe Aug 23 '17 at 10:05
18

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).

8

@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.

  • Does this work because the code block runs in a subshell? – Pysis Aug 23 '17 at 20:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.