Thursday Sep 01, 2005

Sad shell programming problem

While I was away an email ended up in my mail box like this:

I have a question on scripting ...

I want a "timedwait" for a background process started from a shellscript, i.e. do something like:

while [ 1 ]; do
        start_bg_job &
        "timedwait $! 30" || kill -9 $?
        cleanup
done

i.e. wait for the background job termination - but no more than 30 secs, if it didn't finish then kill it hard.

There were a couple of replies but none of them were “pure” shell scripts but it was weeks ago so who cares. Well it nagged at me last night as I cycled home. There has to be away to do this from the korn shell, and as usual the answer came to me just outside Fairoaks Airport (that is the answer came to me as usual while cycling home rather than outside the Airport.. If all the answers came to me outside the Airport I would be there a lot).


The trick (hack may be more appropriate) is to use a co process and start both the command you wish to run and a sleep command in the background in a sub shell that is the co process. When each of the commands return you echo information as to what to do back to the parent process which reads from the co process and takes the appropriate action.


So I ended up with this shell function:


#!/bin/ksh -p

# run_n_wait “command” [timeout]
function run_n_wait
{
        typeset com command time pid arg

        command="$1"
        time=${2:-60}

        ( ( ( $command ) > /dev/null 2>&1 & \\
                echo pid $! ; wait $! ;\\
                echo Done $? ) & \\
         (sleep $time ; echo kill ) & ) |&

         while read -p com arg
         do
                case $com in
                kill)  if [[ "${pid}" != "" ]]
                        then
                                kill ${pid} > /dev/null 2>&1
                                wait ${pid}
                        fi
                        return -1 ;;
                pid) pid=$arg ; arg="" ;;
                Done) return $arg ;;
                esac
        done
}


x=$SECONDS
run_n_wait "/bin/false" 3
echo Slept for $(($SECONDS - $x)) seconds ret $?
x=$SECONDS
run_n_wait "sleep 5 " 
echo Slept for $(($SECONDS - $x)) seconds ret $?
x=$SECONDS
run_n_wait "sleep 60" 3
echo Slept for $(($SECONDS - $x)) seconds ret $?

Yes there are lots of shells that could just do this out of the box but that was not the question. If you have a better way (korn shell, bourne shell only) let me know.


Tags:

About

This is the old blog of Chris Gerhard. It has mostly moved to http://chrisgerhard.wordpress.com

Search

Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today