CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Scheduling / crontab

crontab

Schedule recurring jobs with cron

Beginneressentialschedulingautomation

crontab installs, lists and removes your personal cron table: lines of five time fields plus a command that the cron daemon runs on schedule, such as backups at 02:00 or health checks every 5 minutes. Most cron bugs come from cron's minimal environment, not from the schedule.

Syntaxcrontab [-u USER] { -e | -l | -r | FILE }

Watch it run

Schedule a health check every 5 minutes and a backup at 02:00 for your user, from a file you keep in git.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 4
crontab -l

You don't have a crontab yet. The message goes to stderr and the exit code is 1, which matters if a script does crontab -l > backup.

Anatomy of a command

$
minute*/5

Minute field (0-59). */5 = every 5 minutes: 0, 5, 10... 55.

How it works

The cron daemon (cron on Debian/Ubuntu, crond from cronie on RHEL and Amazon Linux) wakes up once a minute. It reads user crontabs from /var/spool/cron/crontabs/<user> (/var/spool/cron/<user> on RHEL), plus /etc/crontab and /etc/cron.d/*, whose lines have an extra user field. It re-reads a file only when the spool directory's mtime changes. You can't write the spool directly: crontab is setgid crontab, checks /etc/cron.allow and cron.deny, validates your syntax, then installs the file. For each line matching the current minute, cron forks, switches to the user and runs /bin/sh -c 'command' with a minimal environment: HOME, LOGNAME, SHELL=/bin/sh and PATH=/usr/bin:/bin. Your .bashrc and exported variables are not loaded. Output is mailed to MAILTO through the local MTA, and with no MTA it's discarded. When both day-of-month and day-of-week are restricted, a job runs when either matches. Every run is logged as 'CRON[pid]: (user) CMD (...)'.

crontab only installs a file; the cron daemon wakes every minute, matches lines and runs them with a bare environment.

saveinstallwakeread if changedreadfork as kunalstdout/stderrlog CMDYoucrontab -ecrontabsetgid, checksSpool filecrontabs/kunalmode 600/etc/cron.dsystem jobsMinute tickevery :00 seccron daemonruns as root/bin/sh -cminimal envOutputmail or droppedjournalCRON CMD lines
1/8
crontab -e validates and installs

Your editor saves a temp file. crontab checks the five fields of every line and, if they're valid, writes /var/spool/cron/crontabs/kunal. A bad line means nothing is installed.

← → to step

Options you'll actually use

-eEdit your crontab in $EDITOR; it's validated and installed on save
-lPrint your crontab
-rRemove your whole crontab, with no confirmation
-iWith -r: ask before removing (Debian/RHEL)
FILEReplace your crontab with the contents of FILE
-u USERAct on another user's crontab (root only)
*/NEvery N units: */15 in the minute field = every 15 min
A-B, A,BRanges and lists: 1-5 = Mon-Fri, 0,30 = on the hour and half hour
@reboot, @daily, @hourlyShortcuts: once at boot, 0 0 * * *, 0 * * * *
MAILTO=Line at the top: where output goes (empty = nowhere)
PATH=Line at the top: give jobs a real PATH

Common mistakes

0 2 * * * backup.sh

cron's PATH is /usr/bin:/bin and its working directory is $HOME, so relative commands and tools in /usr/local/bin aren't found.

0 2 * * * /home/kunal/bin/backup.sh >> /home/kunal/logs/backup.log 2>&1
0 0 * * * tar czf /backup/$(date +%F).tgz /data

% is special in crontab: it ends the command and the rest becomes stdin. The job runs 'tar czf /backup/$(date +' and fails.

0 0 * * * tar czf /backup/$(date +\%F).tgz /data # or move it into a script
0 9 1 * 1 report.sh, meaning 'the first Monday of the month'

When day-of-month and day-of-week are both set, cron runs on either: the 1st of every month AND every Monday.

0 9 1-7 * * [ "$(date +\%u)" = 1 ] && /opt/report.sh
Scheduling 0 9 * * * and expecting 09:00 local time

cron uses the server's timezone, which is UTC on almost every cloud instance.

Check timedatectl; convert to UTC (or use CRON_TZ= with cronie, or a systemd timer with a timezone)
Running a 10-minute job every 5 minutes

cron starts a new copy whether or not the last one finished; runs overlap and fight over the same files.

*/5 * * * * flock -n /tmp/sync.lock /opt/sync.sh

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Install the example crontab from ~/crontab.example, then list your crontab to confirm.

  2. 2

    Add a job that appends the date to ~/logs/tick.log every minute. Wait a minute and check it ran.

  3. 3

    Find out what environment cron gives your jobs.

  4. 4

    Find the system cron job in /etc/cron.d that deletes old app logs, and say when it runs.

  5. 5

    Back up your crontab to ~/crontab.bak, then remove all your cron jobs.

Related commands

atRun a command once at a later timesystemctlStart, stop, enable and inspect systemd servicessleepPause for a set time (retries, polling, containers)
PreviousjournalctlNextat
Linux / Scheduling / crontab

crontab

Schedule recurring jobs with cron

Beginneressentialschedulingautomation

crontab installs, lists and removes your personal cron table: lines of five time fields plus a command that the cron daemon runs on schedule, such as backups at 02:00 or health checks every 5 minutes. Most cron bugs come from cron's minimal environment, not from the schedule.

Syntaxcrontab [-u USER] { -e | -l | -r | FILE }

Watch it run

Schedule a health check every 5 minutes and a backup at 02:00 for your user, from a file you keep in git.

devops@devops-lab: ~ — zsh — 96×28
➜ ~
Step 1 of 4
crontab -l

You don't have a crontab yet. The message goes to stderr and the exit code is 1, which matters if a script does crontab -l > backup.

Anatomy of a command

$
minute*/5

Minute field (0-59). */5 = every 5 minutes: 0, 5, 10... 55.

How it works

The cron daemon (cron on Debian/Ubuntu, crond from cronie on RHEL and Amazon Linux) wakes up once a minute. It reads user crontabs from /var/spool/cron/crontabs/<user> (/var/spool/cron/<user> on RHEL), plus /etc/crontab and /etc/cron.d/*, whose lines have an extra user field. It re-reads a file only when the spool directory's mtime changes. You can't write the spool directly: crontab is setgid crontab, checks /etc/cron.allow and cron.deny, validates your syntax, then installs the file. For each line matching the current minute, cron forks, switches to the user and runs /bin/sh -c 'command' with a minimal environment: HOME, LOGNAME, SHELL=/bin/sh and PATH=/usr/bin:/bin. Your .bashrc and exported variables are not loaded. Output is mailed to MAILTO through the local MTA, and with no MTA it's discarded. When both day-of-month and day-of-week are restricted, a job runs when either matches. Every run is logged as 'CRON[pid]: (user) CMD (...)'.

crontab only installs a file; the cron daemon wakes every minute, matches lines and runs them with a bare environment.

saveinstallwakeread if changedreadfork as kunalstdout/stderrlog CMDYoucrontab -ecrontabsetgid, checksSpool filecrontabs/kunalmode 600/etc/cron.dsystem jobsMinute tickevery :00 seccron daemonruns as root/bin/sh -cminimal envOutputmail or droppedjournalCRON CMD lines
1/8
crontab -e validates and installs

Your editor saves a temp file. crontab checks the five fields of every line and, if they're valid, writes /var/spool/cron/crontabs/kunal. A bad line means nothing is installed.

← → to step

Options you'll actually use

-eEdit your crontab in $EDITOR; it's validated and installed on save
-lPrint your crontab
-rRemove your whole crontab, with no confirmation
-iWith -r: ask before removing (Debian/RHEL)
FILEReplace your crontab with the contents of FILE
-u USERAct on another user's crontab (root only)
*/NEvery N units: */15 in the minute field = every 15 min
A-B, A,BRanges and lists: 1-5 = Mon-Fri, 0,30 = on the hour and half hour
@reboot, @daily, @hourlyShortcuts: once at boot, 0 0 * * *, 0 * * * *
MAILTO=Line at the top: where output goes (empty = nowhere)
PATH=Line at the top: give jobs a real PATH

Common mistakes

0 2 * * * backup.sh

cron's PATH is /usr/bin:/bin and its working directory is $HOME, so relative commands and tools in /usr/local/bin aren't found.

0 2 * * * /home/kunal/bin/backup.sh >> /home/kunal/logs/backup.log 2>&1
0 0 * * * tar czf /backup/$(date +%F).tgz /data

% is special in crontab: it ends the command and the rest becomes stdin. The job runs 'tar czf /backup/$(date +' and fails.

0 0 * * * tar czf /backup/$(date +\%F).tgz /data # or move it into a script
0 9 1 * 1 report.sh, meaning 'the first Monday of the month'

When day-of-month and day-of-week are both set, cron runs on either: the 1st of every month AND every Monday.

0 9 1-7 * * [ "$(date +\%u)" = 1 ] && /opt/report.sh
Scheduling 0 9 * * * and expecting 09:00 local time

cron uses the server's timezone, which is UTC on almost every cloud instance.

Check timedatectl; convert to UTC (or use CRON_TZ= with cronie, or a systemd timer with a timezone)
Running a 10-minute job every 5 minutes

cron starts a new copy whether or not the last one finished; runs overlap and fight over the same files.

*/5 * * * * flock -n /tmp/sync.lock /opt/sync.sh

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Install the example crontab from ~/crontab.example, then list your crontab to confirm.

  2. 2

    Add a job that appends the date to ~/logs/tick.log every minute. Wait a minute and check it ran.

  3. 3

    Find out what environment cron gives your jobs.

  4. 4

    Find the system cron job in /etc/cron.d that deletes old app logs, and say when it runs.

  5. 5

    Back up your crontab to ~/crontab.bak, then remove all your cron jobs.

Related commands

atRun a command once at a later timesystemctlStart, stop, enable and inspect systemd servicessleepPause for a set time (retries, polling, containers)
PreviousjournalctlNextat