views:

1505

answers:

2

Hi,

I have a command CMD called from my main bourne shell script that takes forever.

I want to modify the script as follows:

  1. Run the command CMD in parallel as a background process ($CMD &).
  2. In the main script, have a loop to monitor the spawned command every few seconds. The loop also echoes some messages to stdout indicating progress of the script.
  3. Exit the loop when the spawned command terminates.
  4. Capture and report the exit code of the spawned process.

    Can someone give me pointers to accomplish this? Thanks, Bob

+1  A: 
#/bin/bash

#pgm to monitor
tail -f /var/log/messages >> /tmp/log&
# background cmd pid
pid=$!
# loop to monitor running background cmd
while :
do
    ps ax | grep $pid | grep -v grep
    ret=$?
    if test "$ret" != "0"
    then
        echo "Monitored pid ended"
        exit
    fi
    sleep 5

done

wait $pid
echo $?
Abu Aqil
Here's a trick to avoid the `grep -v`. You can limit the search to the beginning of the line: `grep '^'$pid` Plus, you can do `ps p $pid -o pid=`, anyway. Also, `tail -f` isn't going to end until you kill it so I don't think it's a very good way to demo this (at least without pointing that out). You might want to redirect the output of your `ps` command to `/dev/null` or it'll go to the screen at every iteration. Your `exit` causes the `wait` to be skipped - it should probably be a `break`. But aren't the `while`/`ps` and the `wait` redundant?
Dennis Williamson
Why does everybody forget about `kill -0 $pid`? It doesn't actually send any signal, only checks that the process is alive, using a shell built-in instead of external processes.
ephemient
+3  A: 

1: In bash, $! holds the PID of the last background process that was executed. That will tell you what process to monitor, anyway.

4: wait <n> waits until the process with ID is complete (it will block until the process completes, so you might not want to call this until you are sure the process is done). After wait returns, the exit code of the process is returned in the variable $?

2, 3: ps or ps | grep " $! " can tell you whether the process is still running. It is up to you how to understand the output and decide how close it is to finishing. (ps | grep isn't idiot-proof. If you have time you can come up with a more robust way to tell whether the process is still running).

Here's a skeleton script:

# simulate a long process that will have an identifiable exit code
(sleep 15 ; /bin/false) &
my_pid=$!

while   ps | grep " $my_pid "     # might also need  | grep -v grep  here
do
    echo $my_pid is still in the ps output. Must still be running.
    sleep 3
done

echo Oh, it looks like the process is done.
wait $my_pid
my_status=$?
echo The exit status of the process was $my_status
mobrule
`ps -p $my_pid -o pid=` neither `grep` is needed.
Dennis Williamson
@Dennis Williamson `ps` has many flavors. Your call doesn't work for me but `ps -p$my_pid` does. Your larger point that `grep` isn't necessary is correct.
mobrule
Hmmm .. actually I can't figure out a good way to avoid grep on Cygwin. `ps -p$pid` always has exit status of 0 whether $pid exists or not. I could say something like `while [ 'ps -p$pid | wc -l' \> 1 ]` but that's hardly an improvement ...
mobrule
`kill -0 $!` is a better way of telling whether a process is still running. It doesn't actually send any signal, only checks that the process is alive, using a shell built-in instead of external processes. As `man 2 kill` says, "If _sig_ is 0, then no signal is sent, but error checking is still performed; this can be used to check for the existence of a process ID or process group ID."
ephemient