tags:

views:

142

answers:

6

I have a bash script runned every day via cron.

In this bash I want to run some command but only every x day (x is fixed and will be 3, 4 or 5 I don't know at the moment)

I can test if the remainder of the division day of month / x equal 0

day_of_month % x = 0

I will work on a single month but not always between to month, for example months april - may with x = 3

1 2 3 4 5 6 7 8 9 ... 27 28 29 30 31 1 2 3 4 5 6 7 8 9 ... 27 28 29 30 
    x     x     x ...  x        x        x     x     x ...  x        x

It not a big deal, but is there any other way to do this ?

PS : I don't want to explode my script and make 2 cron jobs (one every day : *, the other evevery x day : */x)

+1  A: 

I would export a system variable with last date of execution and calculate the interval from it. It wouldn't work after a restart but I assume in this case the interval should be restored.

pedromarce
The variable would not be seen on subsequent runs of the `cron` job. Export works with children, not parents. You could, however, put your date in a file in `/var/run` and read it to control execution. That would also survive reboots.
Dennis Williamson
+2  A: 

Using cron sounds the like the proper idea actually, because that is what cron is made for.

One idea though to solve your 'across months' problems: don't think in months, instead check whether the time-in-seconds-since-epoch % x*seconds-per-day is 0 ...

ankon
+5  A: 

One easy solution would be to use "day of year" instead of day of month. Then there'd be no problem with different month lengths. You'd still get problems at the end of year, of course. The "day of year" is available via date +%j.

If that is still not acceptable, you can use the seconds since 1970 (date +%s), and divide by days*60*60, then use the remainder of that. You'd still get problems with leap seconds, but otherwise it should be correct.

sleske
Good idea, thanks
voidAndAny
+1 for mentioning leap seconds :)
retracile
A: 

Does your job need to run every day? That is, does it do something on those days when your calculation does not result in a 0. If not, you could set up a job in cron thus:

0 12 3,6,9,12,15,18,21,24,27,30 * * <your job>

and it would run every third day (at 12 noon in my example).

I'm pretty sure that "Feb 30" would be safely ignored.

dave
yes my bash script need to be run every day
voidAndAny
+1  A: 

Have a look at the at command

Using that you can tell a script to call itself at a later date.

From manpage:

For example, to run a job at 4pm three days from now, you would do at 4pm + 3 days, to run a job at 10:00am on July 31, you would do at 10am Jul 31 and to run a job at 1am tomorrow, you would do at 1am tomorrow.

Nifle
A: 

If I had this problem, I would tell cron to run my script once every day, and inside the script I would calculate whether or not work needs to be done. That way, you have full control over it.

For example,

dayno=`date +%d`
let divided=daynum/3
if [ $divided == 0 ] ;  then 
  exit 0
fi
# real work begins here

This script would work on any system that uses bash.

Michael Dillon