tags:

views:

253

answers:

4

I want to programatically change the hour which certain cron jobs execute. I'm not sure whether I'm going about this the right way, but here's the plan.

Jobs which are subject to change will have a comment on the end of the line "#change-enabled".

15 5 7,14,21,28 * * /path/to/executable1 #change-enabled
15 * * * * /path/to/executable2
45 5 */2 * * /path/to/executable3 #change-enabled

Then I want to pipe the output from "crontab -l" through sed to catch and alter jobs with that comment on the end, and pipe the results of that through "crontab -".

// Edit

My gut tells me to stay away from doing this as root because the new hour is determined using data from a 3rd party. (Google Analytics Data Export API) So /etc/cron.d/ is something I'm going to stay away from for this application.

Here is the command which has been working with all of my current cron jobs during debugging. I've been using "date +%l" in place of "/home/user/slow-hour" and leaving off the "| cron -" to see what my gets printed.

crontab -l | sed -e "s/^\([^ ]*\) [0-9]* \(.*#change-enabled\)/\1`/home/user/slow-hour` \2/" | crontab -

The contents of ~/slow-hour will be a script which fetches hourly data for website profiles at Google Analytics and looks for the slowest hour. In the event of any error whatsoever that script will return 1AM, mail me a notice and then bail.

In order the reduce the likelihood of a days execution being skipped due to the slow hour being earlier than the current hour, the automated cron rescheduler will be set to run at midnight and the earliest hour ~/slow-hour will return will be 1AM.

Based on my manual cron job adjustments in the past, I don't anticipate excluding midnight from being the slowest hour being a problem in my case.

+1  A: 

crontab -l | sed '/change-enabled$/s/pat/repl/' | crontab -

William Pursell
+1  A: 

You can do that, but there's a better way (provided, you've got root access).

Instead of altering crontab, split jobs into related groups. For each group put a new file in /etc/cron.d/{jobname}. This way you can just regenerate one script without problems - no sed magic needed. Split everything that can change into separate files, so that you just write a new file in place of the old one and don't mess with the entries that don't need changing.

The only difference is the syntax. Instead of:

<time> <command>

you have to put there:

<time> <user> <command>

so that the job is run with the correct rights.

Example - instead of 'crontab -l | sed -e 's/....somejob.../.../ | crontab ..' just run 'echo .... > /etc/cron.d/somejob'

viraptor
I almost went with this, the need for root made me think twice though.
joebert
Fair enough. Although it can be done securely - run an 'updater' cron job that expects a file containing *only* an hour (one number, no letters, symbols, etc.) and if it's correct - updates the cron job. Then run a script creating that file, as your unprivileged user, or 'nobody'.
viraptor
A: 
crontab -l | sed -re '/# *change-enabled *$/s/^([^ ]+) [^ ]+/\1 new_hour/' | crontab -
chaos
I get the following error with this as-is. "sed: -e expression #1, char 2: extra characters after command"
joebert
`sed` flavor issue, I guess. Edited to hopefully be more globally compatible.
chaos
+1  A: 

Assuming you want to set the hour to 8, one command would be

sed -e 's/\([0-9]*\) [0-9]* \(.*#change-enabled\)/\1 8 \2/'
Martin v. Löwis
Doesn't work if the minute setting contains non-numeric characters, like `*/2`.
chaos
I based my pattern off of this answer, swapped the quotes out with ones which allow execution in the replacement string, and swapped out the 8 as needed.
joebert