views:

228

answers:

5

I want to run a script once day (and only on weekends), however, I cannot use cron job for that.

I was thinking about having an infinite while loop, sleep for 24 hours, check if it is a weekend, and if so execute the script.

What it's a good solution under bash on linux?

my current implementation:

#! /bin/bash

 while [ true ]; do
    if [[ $(date +%u) -lt 6 ]]; then
               ./program
        else
             echo Today is a weekend, processing is skipped. Back to sleep.
    fi
    sleep  86400
done

And I will launch this script at 5 pm.

A: 

The problem with using a long sleep is that your program's idea of what time it is will drift. It would be better just to loop with short sleep periods and check to see if you're within the desired window.

If your admins don't allow you to use cron, they may not be happy that you're circumventing that restriction.

However, here's a rough outline:

while :
do
    dow=$(date +%u)
    if (( dow == 6 || dow == 7 ))
    # you can check a flag or counter to limit the number of times it's performed
    # or use a more refined date spec than just whole days (times of day, in other words)
    then
        do_something
        sleep 1h    # or use a smaller or larger interval
    fi
done
Dennis Williamson
Your executing do_something at least 24 times a day on weekends. A fixed sleep of 24 hours won't work because sleep can return early.
Ven'Tatsu
that's pretty much what I came up with. I will post it in the original question
vehomzzz
A: 

Assuming you really can't use cron or at to schedule jobs you will need to write a sleep loop. The details of how you write it will vary based on your requirements.

If you only want to execute once a day you have to worry about short sleeps. The sleep system call that is underneath most languages sleep function doesn't assure you that it will sleep the requested length of time. Your program might sleep for slightly longer than requested or much shorter than requested. You can schedule a sleep for 24 hours, but the OS may wake your program to deliver a signal after a few hours or even after only a few seconds. If your not keeping track of the last run, or your next expected run you can execute multiple times a day.

If you want to execute at a specific time you will need to vary the length of time you sleep. A partial sleep might set you off by half a day and you will need to sleep 12 hours to get back in sync.

You need to account for Daylight Saving/Summer Time. One day a year will have 23 hours, and another will have 25.

You can use something along the lines of this pseudocode:

set next_time_to_run
loop forever
    sleep time_difference_in_seconds(current_time, next_time_to_run)
    if current_time is close to next_time_to_run
        execute code
        update next_time_to_run
    end if
end loop
Ven'Tatsu
+2  A: 

For a Perl solution then take a look at Schedule::Cron CPAN module:

use 5.012;
use warnings;
use Schedule::Cron;

my $cron = Schedule::Cron->new( sub {} );

# add weekend run @ 05:00 
$cron->add_entry('0 5 * * Sat,Sun', sub {
    system './program';
});

$cron->run();

/I3az/

draegtun
+1  A: 

You can use snaked. It is similar to cron, but written in Perl.

Alexandr Ciornii
+6  A: 

Back in the day when there were no per-user crontabs, I often accomplished this using at(1).

#!/bin/sh
... do stuff...
at -f /path/to/me 5pm tomorrow

This way your script runs and schedules itself for the next invocation.

I don't think you can specify a timespec of "next weekend", so you'll just have to reschedule every day and have your script exit (after scheduling the next at job) if it is not a weekend.

Edit: Or instead of scheduling every day, find out what today is and schedule appropriately. e.g.

day=Saturday
if [ $(date +%u) -eq 6 ] ; then day=Sunday ; fi
at -f /path/to/me 5pm next $day

If this script is run on a Saturday, it schedules the next run for next Sunday, otherwise it runs next Saturday. [ $(date +%A) = Saturday ] may be more readable, buts %A will give a locale-specific string so may not work if you change locale.

camh