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?
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:
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.
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:
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With