Command scheduling with cron
Posted by Steve on Mon 13 Dec 2004 at 19:25
Many pieces of system administration can be automated via perl scripts, or shell scripts which run at regular intervals. For example you might have a script to check that your disk isn't full which runs once an hour - informing you if there are problems. The most common mechanism for scheduling commands on Unix systems is via the cron package. This allows users to schedule arbitary commands to run at arbitary times with regular frequency.
In Debian the cron package is installed as part of the base system, and will be running by default.
Cron, as supplied in Debian, has two purposes:
- To run system jobs on a daily/weekly/monthly basis
- To allow users to setup their own schedules
The system schedules are setup when the package is installed, via the creation of some special directories:
/etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/cron.monthly /etc/cron.weekly
Except for the first one which is special, these directories allow scheduling of system-wide jobs in a coarse manner. Any script which is executable and placed inside them will run at the frequency which its name suggests.
For example if you place a script inside /etc/cron.daily it will be executed once per day, every day.
The time that the scripts run in those system-wide directories is not something that an administration typically changes, but the times can be adjusted by editing the file /etc/crontab. The format of this file will be explained shortly.
The normal manner which people use cron is via the crontab command. This allows you to view or edit your crontab file, which is a per-user file containing entries describing commands to execute and the time(s) to execute them.
To display your file you run the following command:
crontab -l
root can view any users crontab file by adding "-u username", for example:
crontab -u skx -l # List skx's crontab file.
The format of these files is fairly simple to understand. Each line is a collection of six fields separated by spaces.
The fields are:
- The number of minutes after the hour (0 to 59)
- The hour in military time (24 hour) format (0 to 23)
- The day of the month (1 to 31)
- The month (1 to 12)
- The day of the week(0 or 7 is Sun, or use name)
- The command to run
More graphically they would look like this:
* * * * * Command to be executed - - - - - | | | | | | | | | +----- Day of week (0-7) | | | +------- Month (1 - 12) | | +--------- Day of month (1 - 31) | +----------- Hour (0 - 23) +------------- Min (0 - 59)
(Each of the first five fields contains only numbers, however they can be left as '*' characters to signify any value is acceptible).
Now that we've seen the structure we should try to ru na couple of examples.
To edit your crontabe file run:
crontab -e
This will launch your default editor upon your crontab file (creating it if necessary). When you save the file and quit your editor it will be installed into the system unless it is found to contain errors.
If you wish to change the editor used to edit the file set the EDITOR environmental variable like this:
export EDITOR=/usr/bin/emacs crontab -e
Now enter the following:
0 * * * * /bin/ls
When you've saved the file and quit your editor you will see a message such as:
crontab: installing new crontab
You can verify that the file contains what you expect with :
crontab -l
Here we've told the cron system to execute the command "/bin/ls" every time the minute equals 0, ie. We're running the command on the hour, every hour.
Any output of the command you run will be sent to you by email, if you wish to stop this then you should cause it to be redirected, as follows:
0 * * * * /bin/ls >/dev/null 2&>1
This causes all output to be redirected to /dev/null - meaning you won't see it.
Now we'll finish with some more examples:
# Run the `something` command every hour on the hour 0 * * * * /sbin/something # Run the `nightly` command at ten minutes past midnight every day 10 0 * * * /bin/nightly # Run the `monday` command every monday at 2 AM 0 2 * * 1 /usr/local/bin/monday
One last tip: If you want to run something very regularly you can use an alternate syntax: Instead of using only single numbers you can use ranges or sets.
A range of numbers indicates that every item in that range will be matched, if you use the following line you'll run a command at 1AM, 2AM, 3AM, and 4AM:
# Use a range of hours matching 1, 2, 3 and 4AM * 1-4 * * * /bin/some-hourly
A set is similar, consisting of a collection of numbers seperated by commas, each item in the list will be matched. The previous example would look like this using sets:
# Use a set of hours matching 1, 2, 3 and 4AM * 1,2,3,4 * * * /bin/some-hourly
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Shelldorado.com has a small collection of scripts - but most things I was thinking of were site-specific.
Cleaning out /tmp, printing reports of the users who are using the most disk space, generating stats pages for a group of web hosts, etc.
If everything could be automated we'd be out of a job !
-- Steve.org.uk
[ Parent | Reply to this comment ]
The messsage is:
/bin/sh: line 1: root: command not found silvere.
[ Parent | Reply to this comment ]
| | | | +----- Day of week (0-6)
?
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Yes, I guess so.
Running :
man 5 crontab
shows:
field allowed values ----- -------------- minute 0-59 hour 0-23 day of month 1-31 month 1-12 (or names, see below) day of week 0-7 (0 or 7 is Sun, or use names)
Steve
--
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
Additionally you can make intervals:
*/15 * * * * /bin/example * */2 * * * /bin/example2
This will run the example script every 15 minutes, and the example2 script every 2 hours.
Use the same syntax in differnt columns for similar effects.
[ Parent | Reply to this comment ]
24 */2 * * * /path/to/script
Or this:
*/24 */2 * * * /path/to/script
Thanks for your answer! [smportal.info]
[ Parent | Reply to this comment ]
/144 * /path/to/script
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
So:
* * */10 * * Command to be executed
This means Every minute, of every hour, every day/10 - should work.
[ Parent | Reply to this comment ]
0 */2 * * * /bin/example2
[ Parent | Reply to this comment ]
Seems redundant to have both (for root).
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Generally it is preferable to use "crontab -e" to edit the root crontab, since the /etc/crontab file is meant as a system file which isn't to be editted.
Whilst you may edit it if you wish you can see from the contents that it is responsible for running things in /etc/cron.daily, etc, so it seems most sensible to leave it alone. (Obviously you could put scripts into /etc/cron.*/ if you wanted them to run with the relevant frequency...)
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Either could happen depending on your version of cron.
By default you'll have cron installed which will not start jobs which should have occurred whilst it was not running. If you install the anacron package then the jobs will run when the computer is turned on next.
[ Parent | Reply to this comment ]
if not is there any aother tools for this kind of task.
[ Parent | Reply to this comment ]
# Use a set of hours matching 1, 2, 3 and 4AM
* 1,2,3,4 * * * /bin/some-hourly
versus
# Use a set of hours matching 1, 2, 3 and 4AM
0 1,2,3,4 * * * /bin/some-hourly
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
"Although cron requires that each entry in a crontab end in a newline character, neither the crontab command nor the cron daemon will detect this error. Instead, the crontab will appear load normally. However, the command will never run. The best choice is to ensure that your crontab has a blank line at the end."
I was chasing this issue for over an hour - I could not figure out why the last cron job in crontab would not run! Just thought I would document it here so the next person does not loose sleep over this!
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
Neither dot in the file names...
automysqlbackup.sh users... BEWARE.
[ Parent | Reply to this comment ]
I am quite a newbie in Linux and I was crashing my head on the wall to understand why my cron scripts were not executed... damn it it's because I have dots in the filename!! Thank you for helping : )
[ Parent | Reply to this comment ]
I dont think any of mine are running!
I seem to have anacron installed also, I wonder if this is inteferring with cron.
[ Parent | Reply to this comment ]
Thanks for your share...
[ Parent | Reply to this comment ]
Was trying to run a .php file, has a . in the name.
Many thanks.
[ Parent | Reply to this comment ]
My cronjob named _.__....____.__.sh would not run either.
Now I know, and knowing is...
[ Parent | Reply to this comment ]
if i want to run 10m after boot ?
@reboot, , .... ???
[ Parent | Reply to this comment ]
If you still want to to this, you could either remove your own cronjob in the script. This gets complicated (crontab -l, piping and grep -v are your friends) or change your script that it only runs once.
For 10 minutes after boot, put it in the init.d/, fork it and put an sleep 600 in front.
@reboot, again init.d is your friend, specifically /etc/init.d/reboot
HTH, micha
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
my crontab -e
0 20 * * * /home/script/to/script1
1 20 * * * /home/script/to/script2
.xsession is:
vlc file:///home/user/to/path1
my script1 is:
echo "vlc file:///home/to/path2">; .xsession
kill -9 `pgrep vlc`
sleep 5
echo "vlc file:///home/user/to/path1">; .xsession
i would like to use my vlc file path 1 as my main playlist and then when the crontab hits the time, it will change to path 2. but when it restarts or shut off, my main will be seen thats why i do have another echo.
[ Parent | Reply to this comment ]
I'm trying to do this on a debian/GUN linux box logged into root. Cron is running pid=1608
crontab -e
#Insert line one below the headers
0-59 * * * * root echo "this is crap"
Leaving a blank line at the bottom and saving the file.
Should this not be spitting this is crap onto my screen every minute?
mroth@theitsystem.com
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
No.
There are two things wrong here:
You've specified "root" which you shouldn't ever do for a personal crontab entry - If you're editing a file via "crontab -e" you just need:
times command
It is only in the system crontab entries, such as /etc/cron.daily/ that you need specify a username.
Secondly the output of cron, if any, is mailed to you.
Take a look at the mail for root and you will most likely see it.
For a personal test I'd just use this:
0-59 * * * * /usr/bin/uptime >> /var/tmp/uptime.log
[ Parent | Reply to this comment ]
[ Send Message | View TheITSystem's Scratchpad ]
I don't even know how I got it to work, but it's working.
Next and probably last question for this topic:
How do I update and/or replace a crontab using Perl? This might be a new topic, but I don't see new topic button anywhere.
[ Parent | Reply to this comment ]
> after
what we have to type to exit crontab command
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Exit the editor and that is all - by default it is probably vim/vi so you can edit by typing "Escape :wq".
If you prefer a different editor run:
EDITOR=/usr/bin/joe crontab -e
Or similar.
[ Parent | Reply to this comment ]
As far as I'm aware, the second redirect *should* read 2>&1 (ampersand after the redirect symbol)
[ Parent | Reply to this comment ]
Thanks.
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
It must be executable. Typically that means "chmod 755 /path/to/script".
[ Parent | Reply to this comment ]