FreeBSD: working with cron April 29, 2010
cron is a very useful tool which permits the scheduling of tasks. cron can run a specified program at a specified time or interval, as
a specified user, capture all the output and either mail it to you, or write it to disk (docs: handbook).
cron does however come with its own set of tricks and traps, which I am documenting below.
cron, crontab files, and crontab
A crontab file specifies all the details of every task to run (docs: manpage).
Crontab files are executed top-to-bottom. Ensure to set all variables before defining tasks.
There is also a program, crontab, which is used to edit users' crontab files (docs: manpage).
The cron daemon monitors every crontab file on the system, and notices all changes automatically (docs: manpage).
system crontab, root crontab, user crontabs
The system crontab's syntax varies slightly from a user's crontab syntax - it specifies which user to run the task as.
vi can be used to edit the system crontab, which is here: /etc/crontab
In general, the system crontab should be left alone.
Each user (including root) has their own crontab file, separate from the system crontab.
User crontab files are stored in /var/cron/tabs - but they are not intended to be edited directly.
Use crontab -l to show the current user's crontab.
Use crontab -e -u Alice to edit Alice's crontab.
Use crontab -e -u root to edit root's crontab.
A user crontab is, when created, blank. Template (based on /etc/crontab):
# user crontab for FreeBSD
#minute hour mday month wday command
# run a task at 23:00 Mon-Fri
0 23 * * 1-5 /usr/home/username/script.sh
# run a task at 23:00 every 3 days
0 23 */3 * * /usr/home/username/script.sh
# run a task at 23:00 every Monday
0 23 * * 1 /usr/home/username/script.sh
crontab file task syntax
Not covered here - covered in detail in the manpage.
From the docs: "Commands are executed by cron when the minute, hour, and month of year fields match the current time, and when at least one of the two day fields (day of month, or day of week) matches the current time"
A cron job uses the HOME and PATH variables in the crontab when executing tasks - it does NOT use the user's HOME and PATH environment variables.
The system crontab sets the PATH variable to /etc:/bin:/sbin:/usr/bin:/usr/sbin - this is very limited, and can cause "not found" errors in scripts that work perfectly on the commandline.
The system crontab sets the HOME variable to /var/log - if running userland tasks, this can cause datafiles to be stored in /var/log
To fix both problems, always use a user's crontab to run scheduled tasks, not the system crontab.
Jobs run from a user's crontab automatically set the HOME variable to the user's home directory.
Use a PATH statement in the user's crontab to set the path as needed.
Defining the full path to all binaries used in scripts is also recommended.
Consider this sample entry in the system crontab file:
# run the daily event at 7:50AM
50 07 * * * root /usr/home/adminuser/script.sh > /usr/home/adminuser/script.txt 2>&1
Any output from the script (on STDOUT) will be saved to /usr/home/adminuser/script.txt which is overwritten if it exists.
Any errors from the script (on STDERR) will also be saved to /usr/home/adminuser/script.txt. This is due to the final
redirection on the above commandline (the "2>&1"), which redirects STDERR to STDOUT (which in turn is redirected to /usr/home/adminuser/script.txt).
If there is no STDOUT redirection in the cron commandline, all output from the job is emailed to the owner of the job (root, in this case).
If there is no STDERR redirection in the cron commandline, all errors from the job are emailed to the owner of the job (root, in this case).
The destination email address can be overridden with the MAILTO variable (defined in the crontab).
Check that the job runs when it should by using an online testing tool, such as this one
First things first, try running the script from the commandline and verify it is working correctly.
Check the email of the user who runs the cron job (by default, cron will email all output of the job to this user).
Check cron's log at /var/log/cron
In your script, try dumping the environment variables to a file and check they are what you are expecting, especially the username, the PATH and the home directory. Eg: