A Bash script to postpone some action for a given time
When a certain job needs to be run often, e.g. some monitoring, but it should do some action only every now and then, postpone can check whether the job was run within some given time by keeping a logfile. In a Bash script, for instance, one could use something along the lines of
if postpone myscriptid "4 hours" ; then echo "action postponed" # do nothing, have a coffee, chill out ... else echo "4 hours passed. Let's go" # do some more nifty stuff, ... fi
Let's say we want to know whether some host is on-line. We want to check every 5 minutes but once the host is on-line we want to receive a message only every 4 hours. With postpone we could put the following into a Cron job which runs every 5 minutes:
ping -c1 84.112.111.156 >/dev/null && { postpone ping156 "4 hours" || echo | mail -s "PC 156 is online" $USER ; }
That is, if the ping -c1
returns TRUE – i.e. the host is on-line and responded to the ping, the remaining part after the && will be executed. postpone ping156 "4 hours"
will check if it has something logged for "ping156" within the last 4 hours, and it will return TRUE if this is the case, i.e. further action should still be postponed. Hence its name :)
If the postpone
returns TRUE execution will stop before the ||. If it returns FALSE mail
will send a message.
Of course, one might want do more sophisticated stuff with the above example. Like when you do not want to be notified you might also do not have to check every 5 minutes, i.e. you could also postpone the ping
.
postpone {jobid} "time interval"
The script is fairly simple. jobid
should be alpha-numeric, and the "time interval"
is handled by date. So everything which is understood by date
should be fine. E.g. 1 hour 27 minutes
.
My script uses date +%s
(a format string for "seconds since 1970-01-01 00:00:00 UTC"). Not all implementations of date
support this. Also, no checking on the validity of "time interval"
is done. For my personal use this is sufficient (at least until proved otherwise).
Just for reference, here are the core parts. For the full script, please, download it: postpone.sh
# get time of last run (or none if there was none) LASTRUN=$(grep "^$JOBID [0-9]" $MYLOGFILE | tail -1 | cut -d' ' -f2,3) # there is only 1 case where we return 0 and do nothing else: # that is when there was a previous run logged and $POSTPONE time is not yet over if [ "/$LASTRUN/" != '//' ] ; then # check time of last run # i.e. return 0 if stored date + POSTPONE is in future NOWSECONDS=$(date +%s) LASTRUNSECONDS=$(date -d "$LASTRUN" +%s) POSTPONESECONDS=$(date -d "now + $POSTPONE" +%s) POSTPONESECONDS=$((POSTPONESECONDS-NOWSECONDS)) test $((LASTRUNSECONDS+POSTPONESECONDS)) -gt $NOWSECONDS && exit 0 fi