Cron

From Helpful
Jump to: navigation, search
These are primarily notes
It won't be complete in any sense.
It exists to contain fragments of useful information.
This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)


Crontab

/etc/crontab is the configuration file for the cron daemon, which runs processes at scheduled times.

It is commonly used to do maintenance like cleaning/checking databases, run things like updatedb (for the locate command), collect data at regular intervals, rebuild reports, and anything else that is handy when regular and/or scheduled.


Some cron daemons will catch up on jobs scheduled to be run when the computer was off, some won't(verify).

In some cases there is only a system crontab, while some cron daemons support user crontabs (in which case root's crontab acts as the system one).


Editing

As root you can edit /etc/crontab and restart (possibly reload) the cron daemon. However, it is easier to:

crontab -e

This will create a temporary file to be edited, run your configured EDITOR, and cause your new crontab to be loaded into cron.


Notes:

  • If your cron daemon supports user crontabs, this command will work for non-root users too.
  • Using crontab -l to list list (display) the crontab may also be useful.
  • when root, you can edit a specific users's crontab with crontab -u username -e


Format and examples

The lines consist of five time restrictions and a command to run, with space separation.


For each time restriction you can use * as a 'no restriction' / wildcard.

The ranges are 0-59 for minute, 0-23 for hour, 1-31 for day of month, 1-12 for month.

Day of week can be three-letter english names, or 0 for sun, 1 for mon, 2 for tue, 3 for wed, 4 for thu, 5 for fri, 6 for sat. On most systems 7 is also valid and means mon.

Examples:

#m    h    dom m dow   cmd
*     *      * * *     echo "Every minute"
*/4   *      * * *     echo "Every four minutes"
*/30  *      * * *     echo "Every thirty minutes"
1,31  *      * * *     echo "Every thirty minutes (more adjustable)"
10    0,8,16 * * *     echo "Thrice daily - 0:10AM, 8:10AM, 16:10PM"
5     4      * * Sat   echo "Saturday 04:05 maintenance"
0     *      * * *     echo "Every hour"
0     0      * * *     echo "Midnight daily"
0     0     13 * 5     echo "Friday the thirteenth (midnight)"
0     9-17   * * 1-5   echo "Whole hours between 9AM and 5PM, from monday 'til friday"
30    *      1 * *     echo "Every half-past-an-hour on the first day of each month"
0     0      2 6 *     echo "It's June second, John's birthday"
0     0      2 6 1     echo "June second, but only if it's a monday"
1-5/2 0      * * *     echo "One, three, and five minutes past each hour"

See also things like:


Don't forget a newline on the last line, or that line may not be used.

Editing via
crontab -e
will usually complain about that.

Since stdout of cronjobs usually gets mailed to you, entries like the above ought to be a good test of whether they get triggered at the times you expect.

Some cron daemons are more permissive than others. For example, 1-5,31-35 would be rejected by some, so check that things work before leaving them.

Running as specific users

Logging

If a command produces output it is mailed to you.

Depending on the specific cron, it may be that only stdout or stderr is mailed to you. Check how yours works / is conigured.

You may wish to do some redirection, e.g. throw away stdout but keep stderr.

>/dev/null  2>&1            # throw away stdout,               and mail stderr (by making it stdout)
>>/home/mydir/cronlog 2>&1  # append stdout in user's directory,   mail stderr
>/dev/null                  # throw away stdout explicitly
2>&1                        # Mail both stderr and stdout. Note that since both are probably buffered,
                            #  they can get interleaved


Note: You can disable logging by starting the cron entry with a tilde (~) (verify)


Debugging

Mailing

'mailed to you' will on many linux hosts mean "delivered to a local mailbox". In which case you won't see it until you look.

Many hosts also aren't directly capable of sending mail on the internet, or not without hardcoding passwords. (though there's a decent chance within universities and businesses)


On your own hosts, an easy-enough alternative is to send via something that allows SMTP

such as gmail's, with an app-specific password to avoid putting your own in there, and to have it be revokable.

See e.g. these instructions for SSMTP.


Keep in mind that mail daemons will reject overly large mail. Logging details to a file is the safer option, but you may still want to mail a summary.

This also argues for sending watchdog emails.


Cron and environment

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)


Cron runs in a restricted environment, and scripts run as, well, scripts, so assume no implicit inclusion of profile/bashrc stuff.

This is a good default, for safety, and to avoid a mess.


Any script that needs more environment should either

  • draw it in explicitly (e.g. sourcing something from the system)
makes sense for scrips that normally do that anyway
  • be given that explicitly
some cron implementations allow env to be set in the crontab (global to all cronjobs)
the more generic solution is to put exports before the command, though this may be messy.
the cleaner solution may be to source such exports from a file.


While debugging you may like a temporary:

* * * * *  printenv > /tmp/cronenv

There's a suggestion here that you can get a good imitation of that environment to test scripts in outside of cron:

env - `cat /tmp/cronenv` /bin/sh


Note also that crontab is using /bin/sh which might e.g. be be dash rather than bash or whatever else you prefer.

So write your scripts with shebangs.

For loose commands to work under a specific shell,

  • you may wish to explicitly name a shell,
  • or use SHELL to have crontab to use a specific shell instead.