Automate Raspberry Pi tasks with crontab

0

I have a Raspberry Pi at home that I use to automate several things. For example, my printer is old enough that it doesn’t support networking, so it’s connected to the Raspberry Pi, which shares the printer to my home network using CUPS. I also use the Raspberry Pi as an at-home web server to work on websites, and as a “file server” of sorts by using SFTP from my file manager.

This became somewhat less useful last year when my Internet provider “upgraded” the home WiFi router. The new router has an added security feature where it disconnects any device from the network after about two or three days. Without a network connection, I can’t print, backup files, or work on web pages.

Restarting the Raspberry Pi would put it back on the network. So I needed to find a way to restart the Raspberry Pi every other day. And I needed it to happen automatically, and gracefully, when I wasn’t likely to use it. That’s the perfect use case for cron and crontab.

Using ‘cron’ and ‘crontab’

On Unix-like systems, cron is the system that executes tasks at specific times. The jobs that run, and when they run, are controlled using a special file called the crontab. Every user can create their own crontab to run tasks according to their own schedule.

The crontab file is arranged like a plain text “table” with fields that define the time, day, month, and day of the week to run the job. You can find detailed information about the crontab file in the crontab(1) online manual page, with this command:

$ man 5 crontab

The classic fields of the crontab file are:

FieldRange of values
1. Minute0 to 59
2. Hour0 to 23
3. Day of month1 to 31
4. Month1 to 12
5. Day of week0 to 6
6. Command to run(enter the full command here)

Modern crontab implementations, like the one on Linux, also support extensions to these fields. For example, the Vixie cron implementation (by Paul Vixie) on most Linux distributions also accepts 0 to 7 as days of the week, where 0 and 7 are the same (Sunday). You can also use names for the months and days of the week, such as sun for Sunday or jan for January. But I like using numbers, so I’ll use that here.

For example, let’s say you needed to run a tar backup of a website, every Sunday at 6:00 AM. You can create this crontab entry:

0 6 * * 0 /bin/tar czf $HOME/website.tar.gz /var/www/html

The first two fields indicate 0 for the minutes and 6 for the hour. The fifth field says 0 for the day of the week, which means “Sunday.” The third and fourth fields are * to mean “any day of the month” and “any month.” Together, these five fields will execute the tar backup every Sunday at 6:00 AM.

To enter the crontab file into the cron system, you need to use the crontab command. If your crontab file is called jobs, then you would type this:

$ crontab jobs

You can verify the contents of the crontab file with crontab -l to list (-l) the contents of the file. You can also erase your crontab from the system with crontab -r to remove (-r) the file.

Scheduled reboot

In my case, I needed to reboot the Raspberry Pi before the router took it off the network. One way to do this is with the telinit command, to change the “System V” run level. On Linux systems that run systemd, this executes the appropriate systemctl command. But I learned on original Unix systems, so I prefer telinit.

To reboot every day at 7:00 AM, I started by creating this crontab file for the root user:

0 7 * * * /sbin/telinit 6

The first two fields are 0 for the minutes and 7 for the hour, with * for all of the other fields; this will run at 7:00 AM every day. I saved this file as /root/jobs and I saved it into the system with this command as root:

# crontab /root/jobs

But I didn’t need to reboot every day; I only needed to reboot every other day. And Vixie cron has a neat syntax where you can specify / and then a number to create an alternate schedule. For example, 0-30/2 for “minutes” would run a job every other minute: “:00,” “:02,” “:04,” … and so on until “:26,” “:28,” and “:30.” This runs on even minutes because “minute” can have values from 0 to 59, and zero is an even number.

To reboot my Raspberry Pi every other day, I updated the crontab entry to use */2 for “day of the month.” This runs the job every other day: 1, 3, 5, … until 27, 29, and 31. These are odd days because “day of the month” is a value between 1 and 31, and 1 is an odd number.

0 7 */2 * * /sbin/telinit 6

With this entry, my Raspberry Pi rebooted itself at 7:00 AM every other day of the month: June 1, June 3, June 5, … and so on for the rest of the month.

Combining jobs

I figured as long as the Raspberry Pi would reboot every other day, I might as well apply updates at the same time. For that, I wanted to run the dnf command to install any updates, then use telinit to reboot the system.

When you need to combine multiple tasks into a single crontab job, I recommend collecting the commands into a script. In my case, I created this Bash script called /root/bin/update_reboot to run dnf and telinit, plus keep a log of what it did:

#!/bin/bash
# apply updates, reboot anyway

logdir=/root/log
[ -d $logdir ] || mkdir -p $logdir

today=$(date '+%d')

dnf -y update > $logdir/dnf_update.$today.log
telinit 6

In this script, I wanted to keep a private log in /root/log to capture the output from the dnf command. The two lines that set the logdir variable and run mkdir ensure that my /root/log directory is present, so I have a place to store logs.

I use the $() shell expansion to run date to print today’s day of the month as a zero-padded number, so I can use the date as part of the log file’s name when I run the dnf command to apply all updates. The last line reboots the system for me.

Automating tasks made easy

While job automation might sound like something that only system administrators do, it’s a feature that anyone can use. If you need to do a task on a regular schedule, explore how you can use crontab to do the repetitive work for you.