Terminate shell script after a specified time

I have a shell script that checks a file state.txt, deletes fit.bin if state.txt is empty. I cron this at 2am, I will want the script to stop by 8am irrespective of the value of state.txt, any ideas?

#!/usr/bin/ksh


while true; do


if [[ -s ~/state.txt ]] ; then

echo

else

rm ~/fit.bin

exit

fi ;


sleep 961

done

exit

Maybe i oversee something, but i think you are doing it more complicated than necessary: put one script in cron at 2 am, put a second one which kills the first one (if it is running at all) in cron at 8 am. You can create a "PID file" at the start of the first script which you remove at program end:

#! /bin/ksh
typeset fPID="/var/run/${0##*/}"

trap "rm -f $fPID" 0

if [ ! -e "$fPID" ] ; then
     print - "$$" > "$fPID"
else
     print -u2 "Error: Program already running"
     exit 2
fi

[.... your script code here ....]

exit 0

This is your work script, which you will start at 2 am. It cannot be started twice (the second instance would terminate). Trap 0 is a "virtual trap" (for lack of a better word), which is not executed upon getting a certain signal but on exiting the shell process (^= terminating the script in any way).

The content of the PID file is only the PID of the running script instance.

Your termination script looks like this:

#! /bin/ksh

typeset fPID="/var/run/yourscript"

if [ -e "$fPID" ] ; then
     kill -15 $(cat "$fPID")
     sleep 5
     kill -9 $(cat "$fPID")         # in case the script doesn't end itself
     rm -f "$fPID"
else
     print -u2 "Warning: yourscript already terminated"
fi

[.....put any cleanup code here.....]

exit 0

Note that both scripts are only rough sketches. You might want to add all sorts of checks, ifs and whens.

I hope this helps.

bakunin

Thanks bakunin. For example, if script terminates successfully at 2:30am, and the PID is reassigned to another process before 8am, won't that cause a process to be terminated wrongfully when the second script is run at 8am??

You can cobble something up like...check the current time and break out of the infinite loop and exit if it's 8 am...

First: it is highly unlikely that the PID is recycled so fastly. PIDs are - for a reason - supposed to be almost random.

Second: even this small chance is further reduced to absolute zero because the terminating script will delete its PID file upon ending. "trap 0" is executed every time the script ends, regardless of how it ends. The action part of the cleanup script will only run when the PID file exists, not when the PID is in use. This means: when the script terminates at 2:30 it will remove the PID file, at 8:00 the cleanup script will start, fail to find a PID script (the "if [ - e file..." will evaluate to "false") and the cleanup script will do nothing (in fact it will issue the warning, see the else-part).

I hope this helps.

bakunin

1 Like

Consider the following:

PID=$$
# The self killer
(sleep 30;kill $PID)&

# The program
while [ T ]; do
   date
   sleep 2
done
2 Likes
#!/usr/bin/ksh
loop=24
#24x900 = 6 hours
while [ $loop -gt 0 ]; do
 if [[ -s ~/state.txt ]] ; then
  echo
 else
  rm ~/fit.bin
  exit
 fi
 sleep 900
 loop=$((loop - 1))
done

Dear cjcox,

This is an elegant solution, and the one-liner that can be inserted into any script. I didn't bother with PID=$$ , I just issue the kill direct at $$ and it worked very well.

:cool:

Robin

There could be cases on old Unix especially where having a subprocess kill it's parent could result in a zombie... so might have to disassociate the subprocess using something like a nohup that disconnects from the pseudo tty, etc...

But in general, it works (everything is Linux nowadays)