Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simultaneously watch for signals and process exit in Bourne shell

I have a Bourne shell (/bin/sh) script (for portability) that wants to monitor another program. It should start the other program, then wait for it to exit. When the second program exits, it does some final work and exits itself. The catch is that the script needs to also respond to a signals (eg USR2) and do some work when those signals show up.

My naive implementation is:

#! /bin/sh
echo $$
trap 'echo Respond to USR2' USR2
/bin/sleep 120 &
pid=$!
wait $pid
echo $pid exited with $?
echo Doing final cleanup

This doesn't work. If I send the shell SIGUSR2, the trap fires as expected, but wait also finishes, returning 140. The /bin/sleep continues on its merry way. Typical output:

28849
Respond to USR2
28850 exited with 140
Doing final cleanup

This behaviour is consistent between dash and bash, the two Bourne shell derivatives I have convenient access to.

My current work around is to spin loop waiting for the child PID to disappear, probing with kill. Spin looping seems wasteful, and enlarges the window where my script might erroneously be waiting for the wrong process if PIDs are being rapidly reused.

#! /bin/sh
echo $$
trap 'echo Respond to USR2' USR2
/bin/sleep 15 &
pid=$!
while /bin/kill -0 $pid 2> /dev/null; do
    echo waiting...
    sleep 2
done
echo Doing final cleanup

Is there a better solution given my goal of simultaneously waiting for another process to exit and being able to respond to signals?

like image 303
Alan De Smet Avatar asked Jul 20 '12 20:07

Alan De Smet


People also ask

How to avoid termination from signals sent to a process?

Because most signals sent to a process executing a shell script cause the script to terminate, the next topic describes how to have a script avoid termination from specified signals. The Korn shell has 46 defined signals. Each signal has a name and a number associated with it. Typing the ‘ kill -l ‘ command displays this list:

What is a signal in shell script?

Shell Signal Values A signal is a message that some abnormal event has taken place or a message requesting another process do something. The signal is sent from one process to another process. Typically, a process sends a signal to one of its own subprocesses.

How many signals does the Korn shell have?

The Korn shell has 46 defined signals. Each signal has a name and a number associated with it. Typing the ‘ kill -l ‘ command displays this list:

Why do signals cause a script to terminate?

Because most signals sent to a process executing a shell script cause the script to terminate, the next topic describes how to have a script avoid termination from specified signals. The Korn shell has 46 defined signals.


1 Answers

You could do:

while wait $pid; test $? -gt 128; do
    kill -0 $pid 2> /dev/null || break;
done

But note the following from the sh standard:

If the exit status of wait is greater than 128, there is no way for the application to know if the waited-for process exited with that value or was killed by a signal. Since most utilities exit with small values, there is seldom any ambiguity. Even in the ambiguous cases, most applications just need to know that the asynchronous job failed; it does not matter whether it detected an error and failed or was killed and did not complete its job normally.

In this case, the ambiguity is slightly different. You don't know if wait was interrupted by the signal or if the child was terminated by a signal.

like image 92
William Pursell Avatar answered Oct 08 '22 16:10

William Pursell