1

I'm trying to write signal handlers in Bash scripts, testing under a Ubuntu 16.04 machine. Here I'm using the trap command:

#!/bin/bash

trap "echo hi!" SIGINT SIGTERM

echo "pid is $$"
while true; do
    sleep 1;
done

After running ./test.sh, pressing Ctrl+C gives me immediate hi! message under the current terminal. However, kill <pid> under another terminal has a 1 second delay printing hi!.

Can anybody tell why there the difference is? Is there a way that always trigger trap command immediately no matter what is going on? (like a sleep loop).

2 Answers 2

2

Can anybody tell why there the difference is?

Ctrl+C gets to sleep as well, while kill <pid> doesn't. In effect the latter way needs sleep to exit by itself before hi! is printed. What you call "1 second delay" is about 1 second at most and about 0.5 on average (it may take longer if the OS is very busy with other tasks).

You can clearly see the difference by using

pv -qL 1 <<< "0123456789"

instead of sleep 1.

Note that

kill -- -<pid>    # note the minus sign before PID

would send the signal to the entire process group, so to sleep (or pv) as well.


Is there a way that always trigger trap command immediately no matter what is going on?

There is this question How to handle signals in bash during synchronous execution?

From one of the answers:

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. When bash is waiting for an asynchronous command via the wait builtin, the reception of a signal for which a trap has been set will cause the wait builtin to return immediately with an exit status greater than 128, immediately after which the trap is executed.

So, run your external program asynchronously and use wait. Kill it using $!.

In your case this method leads to the following quick and dirty script:

#!/bin/bash

trap 'kill "$!"; echo hi!' SIGINT SIGTERM

echo "pid is $$"
while true; do
    sleep 1 &
    wait
done
2
  • If we don't kill "$!" in trap, will we lost pid of the previous sleep 1 after reception of a signal? In another word, will wait really return, or the OS just switches to execute signal handler then come back to wait later (looks like a return)?
    – dastan
    Commented Feb 15, 2019 at 2:55
  • @dastan "then come back to wait later" -- I think wait is no more. Why won't you test it? You can save the pid to a separate variable if you're afraid you can lose it. Commented Feb 15, 2019 at 6:06
0

Instead of sleep 1 try sleep 1 <&0 & wait and then you'll find it quits right away.

The sleep command will remain running, however.

This works because bash's wait command can be interrupted by a signal, but the internal wait can't be.

Of course <&0 isn't required for sleep, but for other commands that are being run in the background this way, stdin would be disconnected unless we deliberately connect it in this way.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .