Crontab environment variables

By: Shane Harter|Last Updated: Jan 11, 2024

Cron jobs are started in their own shell, with their own environment, and their own environment variables. This guide will show you how to set the environment variables for your cron jobs directly in your crontab files, including some that control the behavior of Cron itself.

Why your crontab environment variables are missing

When you open your terminal you start an interactive shell, in this example using bash, your .bashrc file is automatically invoked. When this script runs, any environment variables it exports are available to every command you run in your terminal session. This method of setting environment variables in your .bashrc is the most common way that persistent environment variables are set, but your cron jobs do not invoke an interactive shell, and your .bashrc is not automatically loaded. This is true even if you specify /bin/bash as your crontab shell.

Cron offers a few possible solutions that we will cover in detail in the next section.

Want alerts if your cron jobs stop working?

Monitor your cron jobs with Cronitor to easily collect output, capture errors and alert you when something goes wrong.

How to set environment variables for your cron jobs

When setting environment variables for your cron jobs, you have several options depending on your specific requirements, including:

  1. Declaring variables directly in your crontab files.
  2. Declaring variables as part of your command line.
  3. Loading variables from a file before executing your command.

1. Declare the variables directly in your crontab

In this example, we are configuring a PATH variable and a custom application variable. When the cron job runs, it will look for example.sh in the PATH provided, and when the command is run, its environment will include the PATH and APP_ENV variables too. You can set as many different variables as you need for your jobs, and they can go anywhere in your crontab file.

 APP_ENV=production
 PATH=/root/it/scripts
 0 0 * * * example.sh

One advantage of setting these variables directly in your crontab is that they are clear and easy to find. Anybody trying to understand the crontab file down the road will see every variable required by its jobs.

Unlike bash scripts, the "export" keyword is not needed and not allowed.

2. Declare the variables as part of your command

When you run a command on Linux and other "posix" operating systems, environment variables can be declared inline, and this works with crontab too. Here you can see an example where two jobs are getting different values for the same variable.

 0 * * * * APP_ENV=production /var/data-analytics/export-to-datalake.py  # Every hour
 0 0 * * * APP_ENV=staging    /var/data-analytics/export-to-datalake.py  # Once a day

This is the best way to set environment variables if you need different values in different jobs. (In this example we are only setting one variable, but you can set as many as needed.)

3. Load variables from a file

When you have a lot of environment variables, or if they are centrally controlled by something like Ansible or Consul, you may have them declared directly in a file that you want to re-use everywhere. In this case, you can source that file directly as part of your command string. Any variables exported in the file will be part of the environment for the job.

 0 * * * * source /var/data-analytics/bootstrap.sh ; /var/data-analytics/export-to-datalake.py

Controlling cron behavior with environment variables

Environment variables declared directly in a crontab file are also available to cron itself, and some can be used to control the behavior of Cron as it runs your jobs. Here are 5 variables you can try in your own crontab:

1. PATH

When a command is run without a fully-qualified path, your shell will look for the command in the locations specified by your PATH variable. If no PATH is set, the only place checked will be the current working directory. When you set a PATH variable, it will be used by cron itself to locate your scripts/binaries.

 PATH="/users/dataproc/bin:/var/data-analytics/bin:/root/it/scripts"

You can add as many locations, usually delimited by a colon, and they will be searched in the order you write them.

Compatibility: Works everywhere

2. MAILTO and MAILFROM

Anything your job writes to stdout or stderr is collected by cron and emailed after your job completes. Often this is an annoying source of spam, especially for frequently-run jobs, and the most common advice to stop the email is to ensure your job never writes to stderr or stdout. That technique is will work to stop emails from a single job, but there’s an easier way to prevent cron from ever sending an email: setting a MAILTO environment variable.

 MAILTO=""

Alternatively, if you find cron emails useful, use MAILTO to specify the recipient email and you can even set a custom "from" address using the MAILFROM variable for easier mail filtering and handling. Note: your host will need a Message Transfer Agent (MTA) that is configured to send external email.

Compatibility: Works everywhere

3. SHELL

By default, cron uses the classic “dash” shell at /bin/sh to invoke your commands, and some features that work at an interactive bash prompt are unavailable in dash. You can tell cron to use bash, zsh or any other shell using the SHELL variable:

 SHELL=/bin/bash

Compatibility: Works everywhere

4. CRON_TZ

Cron jobs are run in whatever timezone the system clock is set to. By default this is UTC, but cron jobs are commonly used to perform actions based on wall clock time in different places around the world. By adding a CRON_TZ declaration in your crontab, you can control the timezone that Cron uses when starting your jobs.

 CRON_TZ=America/New_York

Compatibility: Sometimes this is called TZ. See man 5 crontab for details.

5. RANDOM_DELAY

Some implementations of cron, including anacron, allow random delay to all of your jobs is to use the RANDOM_DELAY variable to define the maximum number of minutes to delay.

 RANDOM_DELAY=3

Tip: If you want to add a delay to a single job, you can use the sleep command inline

 0 0 * * * sleep ${RANDOM:0:1} && /path/to/executable