Detecting when a process exited (but did not exit)

I have a program that runs on unix (which I have no control over) that when printing completes, "Completed successfully" but does not exit. I want to automatically detect when a process is finished (by checking the command output) so that I can kill the process and so that I can continue with other activities. The difficulty comes from the fact that I want to be able to simultaneously execute the multiplicity of these scripts. (One action I need to perform requires the script to be called with different inputs, but every time the script is executed it takes a while to return and so I want to do them in parallel)

Has anyone done something similar to this? I could redirect the stderr and stdout output of the command to a temporary file with an arbitrary filename, and then the tail of the file and pipe to grep for end conditions (e.g. certain log lines). The problem is, of course, the -f tail will keep working, and therefore it will never exit. Should I question? If so, what's the best approach?

+2


a source to share


7 replies


#! / Usr / bin / expect



spawn / home / foo / myjob
wait for "completed successfully"

+2


a source


You don't need a survey. You can use the inotify tools like inotifywait to detect when the output file was modified, then grep it and kill the process if necessary. Happy hunting!



+2


a source


Here's my kick in it, it works really well but quite spam because every time kill is called a killed message echoing the whole subshell script is output to the console and I can't suppress it. I'll update if I find a way to get rid of the spam (by the way, redirecting stdout and stderr to / dev / null doesn't help.)

Note. You need bash4 for this; $BASHPID

only available with 4's and $$

not an alternative because it gives the pid of the parent shell, not the subshell.

!/bin/bash

for i in {1..8}; do
  (
    mypid=$BASHPID
    (
      #subshell to simulate started process
      sleep 2
      echo finished
      while : ; do
        :
      done
    ) | \
    {
      while read line; do
        if [[ $line == finished ]]; then
          break;
        fi
      done
      echo process done, killing $mypid...
      kill -9 $mypid
    }
  ) &
done
wait

      

+1


a source


The following shell script will invoke your real command, the output of the pipeline to the tee, which will write to the fifo. The wrapper script will kill your real command when the expected line is copied from the fifo:

#!/bin/bash

# cmd to run
expected_output=$1
shift
cmd=("$@")
# where to read commands output
mkfifo /tmp/killonoutput.$$
# start cmd async 
"${cmd[@]}"|tee /tmp/killonoutput.$$ 2>/dev/null &

if grep -q --max-count=1 "$expected_output" /tmp/killonoutput.$$;then
    kill %1 
    echo "Killed ${cmd[@]}" 
fi
# grep returned so fifo was closed
rm  /tmp/killonoutput.$$

      

Execution example:

./killonoutput.sh "Finished" bash -c "echo sleeping;sleep 3;echo Finished; sleep 10000" 
sleeping
Finished
Killed bash -c echo sleeping;sleep 3;echo Finished; sleep 10000
./killonoutput.sh: line 17: 19553 Terminated              "${cmd[@]}"
     19554                       | tee /tmp/killonoutput.$$ 2> /dev/null

      

+1


a source


This might be overkill for bash, maybe? if you are using python you can use a module subprocess

to open a communication channel between your own program and your child scripts. even better, you could use a module threading

to run multiple runs of a child script in parallel.

Does the script output anything AFTER EXECUTING "completed successfully"? if not, you can simply poll for the last x characters it outputted (to a random file, for example, you suggested, perhaps using tail -n 1

to get the last line) and see if you just saw "succeeded". but if the script keeps printing stuff, you can skip the line.

or you could grep

exit for "completed successfully".

0


a source


A few random ideas. (1) If this is your program, you can modify it to be more useful. (2) Looking at the process list (ps ax), you should see how it jumps to the expected I / O time when it tries to display the Completed message. (3) I believe that pseudo ethnies exist for this purpose, so you can watch their live performance without having to spoof temporary files.

0


a source


First possible solution:
your_program> tempfile1
grep -i "Completed successfully" tempfile1; if [$? -eq 0]; then i = `pidof your_program`; kill $ i; fi

The first is redirection. The second checks the exit status of grep. If it's 0 (success), it gets the pid of your program and kills it.
It was a "mental" exercise. It should work. The downside is that you can only run one instance of your program at a time, but of course an adaptation can be done and you can run it in parallel.

edit- 05/27/2010 :
Second possible solution:
tail --pid = `pidof your_program` -f -n0 tempfile1 | awk '/ Completed / {if ($ 1 == "Completed") {system ("i =` pidof your_program`; kill $ i ")}}' &

Well, with that long line, you don't need the / crontab loop anymore. Explanation:
-pid = `pidof your_program` picks up the tail after the specified PID is finished. Thus, when the program is killed, the tail dies with it.
-n0 ignores other "completed" statements in tempfile1 (so you don't have to worry about always truncating tempfile1 first).
awk executes the Completed request thrown by your program, and part of it {system}

does kill on your program.
Also, do not forget &

at the end, since he founds the whole thing.
Enjoy.

0


a source







All Articles