Run a cronjob at the end of every year

At the end of every year, I need to create some new directories to hold log files with the directory name reflecting the new year on a CentOS Linux system. To create those directories on the last day of the year, December 31, I can use the cron utility found on Linux/Unix and OS X/MacOS systems to schedule a cronjob to run on the last day of the year. I can edit the crontab file that holds jobs to be run at a scheduled time or times by issuing the crontab command crontab -e, which will allow me to edit the file with the vi editor. If the vi editor is the default editor, which it likely is, but you are unfamiliar with that editor, you can change the editor for the current login session to the GNU nano text editor, which may be easier to use for someone unfamiliar with the vi text editor, by issuing the following command at the command line.

export EDITOR="/usr/bin/nano"

The value will be reset when you log off or you can reset it manually with the command below:

export EDITOR="/usr/bin/vi"

I can put the following line in the crontab file to run my script named end-of-year-dirs at 7:00 AM on December 31 of every year. When you add a new entry, be sure to hit the Enter key at the end of the line.

0 7 31 DEC * /home/jdoe/scripts/end-of-year-dirs

The meaning of each of the six fields is explained below. Each line of the crontab file has the following format with 6 fields per entry:

 minutehourday of monthmonth day of weekcommand
Allowed values 0-59 0-23 1-31 1-12 or JAN-DEC 0-6 or SUN-SAT, though 7 is also Sunday on some systems command to be run

An asterisk, "*", in any of the date/time fields can represent any value. E.g., putting an asterisk in the month field would indicate the command is to be run every month. The following characters may also be used:

*any value An asterisk can be used to represent the entire range of allowed values.
,value list separator Commas are used to separate items of a list. E.g., using "MON,WED,FRI" in the 5th field (day of week) means Mondays, Wednesdays and Fridays.
-range of values E.g., 10-15 in the day of month field would indicate days 10 through 15, including days 10 and 15.
/step values Step values can be used in conjunction with ranges. Following a range with "/<number>" specifies skips of the number's value through the range. For example, "0-23/2" can be used in the "hours" field to specify command execution for every other hour (the alternative in the V7 standard is "0,2,4,6,8,10,12,14,16,18,20,22"). Step values are also permitted after an asterisk, so if specifying a job to be run every two hours, you can use "*/2".

The following non-standard macros can be used on some systems, e.g., CentOS Linux systems:

Linux Command Line Tutorial For Beginners
Linux Command Line Tutorial
For Beginners
1x1 px

@yearly Run once a year, ie. "0 0 1 1 *".
@annually Run once a year, ie. "0 0 1 1 *".
@monthly Run once a month, ie. "0 0 1 * *".
@weekly Run once a week, ie. "0 0 * * 0".
@daily Run once a day, ie. "0 0 * * *".
@hourly Run once an hour, ie. "0 * * * *".
@reboot Run once after reboot.

As an example of use of @daily, I have the following crontab entry for the root account that runs every day to check on the expiration of a Let's Encrypt X.509 security certificate. Let's Encrypt provides free certificates that expire every 90 days. The daily script will renew a certificate nearing expiration.

@daily /bin/certbot renew

For the end-of-year-dirs script to create a new subdirectory at the end of the year, I can create a Bash script with the following commands in it:

# Create a new directory corresponding to the upcoming year on December 31 of
# every year. The script is run via a crontab entry.

newyear=$(date --date=tomorrow +%Y)

# Check on whether the directory for the current year exists and, if it doesn't,
# create it.
if [ ! -d /home/jdoe/Documents/logs/"$newyear" ]; then
   mkdir /home/jdoe/Documents/logs/"$newyear"

To make the script executable, but not accessible by anyone else, I can change its file permissions to 700 with chmod 700 end-of-year-dirs. You can find information on how to obtain future dates in Bash, see Getting Yesterdays or Tomorrows Day with Bash Shell Date Command.