45

I'm trying to catch the SIGUSR1 signal in a bash script that is sleeping via the sleep command:

#!/bin/bash

trap 'echo "Caught SIGUSR1"' SIGUSR1

echo "Sleeping.  Pid=$$"
while :
do
    sleep 10
    echo "Sleep over"
done

The signal trap works, but the message being echoed is not displayed until the sleep 10 has finished.
It appears the bash signal handling waits until the current command finished before processing the signal.

Is there a way to have it interrupt the running sleep command as soon as it gets the signal, the same way a C program would interrupt the libc sleep() function?

whoan
  • 8,143
  • 4
  • 39
  • 48
John Morris
  • 543
  • 1
  • 4
  • 9

3 Answers3

61
#!/bin/bash

trap 'echo "Caught SIGUSR1"' SIGUSR1

echo "Sleeping.  Pid=$$"
while :
do
   sleep 10 &
   wait $!
   echo "Sleep over"
done
Hans Klünder
  • 2,176
  • 12
  • 8
16

Just a point about the wait after the sleep because I've just made this error in my script:

You should use wait $! instead of wait if, inside your script, you already launched other processes in background

For example, the wait inside the next snippet of code will wait for the termination of both process_1 and sleep 10:

process_1 &
  ...
sleep 10 &
wait  

If you use, instead of wait, wait $! your script will wait only for sleep 10, because $! means PID of last backgrounded process.

Echoes_86
  • 293
  • 3
  • 8
6

Remark that

sleep infinity &
wait

puts the sleep in background, and stops the wait with the signal. This leaves an infinite sleep behind on every signal !

Replace the sleep and wait with

read

and you will be fine.

dirk
  • 69
  • 1
  • 3
  • I don't think it does leave a background process hanging, at least not on MacOS 10.12. – frnhr Nov 25 '16 at 15:01
  • `read` doesn't wait forever. User presses enter -> immediate return. Stdin is connected to `/dev/null` -> immediate return. – Charles Duffy Sep 25 '20 at 21:39
  • `read` trick is interesting thanks. If you want to be sure to never read anything you may use: `read -u 2` in [bash](https://stackoverflow.com/questions/27352868/bash-file-descriptor-3-and-while-read-line) which instructs `read` to get its input from a file description number 2 (which is `stderr` which obviously will never any input). – Sylvain Jun 14 '21 at 05:58