1. Overview

When cron executes a job, it doesn’t load the environmental variables from files like ~/.bashrc, ~/.bash_profile, /etc/profile, and others. This is because cron runs jobs from a non-interactive, non-login shell. This can be a problem, as some programs need environmental variables to function properly.

In this tutorial, we’ll discuss different ways of loading environment variables from a cron job.

2. Setting the BASH_ENV Variable

When we have a bash script in the crontab file, we can use the BASH_ENV variable. We set it with the path to a script, and bash will execute that script before running the job. This way, we can run a script, such as /etc/profile, to load the environment variables we need. Also, this is very handy as we can write any script and call it using BASH_ENV.

Let’s set a job in the crontab file that loads /etc/profile before running the script:

* * * * * BASH_ENV=/etc/profile /home/baeldung/print_envs.sh

Notice, this job runs every minute. Also, let’s write the /home/baeldung/print_envs.sh script to print all environment variables to a temporal file using printenv:

#!/bin/bash
printenv > /tmp/print_envs_result

Now, after setting execution permission to the script with chmod +x /home/baeldung/print_envs.sh, we’ll wait one minute to see the result:

$ wc -l /tmp/print_envs_result
38 /tmp/print_envs_result
$ grep PS1= /tmp/print_envs_result
PS1=\u@\h:\w\$

As we can see, the print_envs.sh script loaded 38 environment variables. For example, it loaded the PS1 variable.

We can also use BASH_ENV to execute a custom script. This is useful when we want to load multiple files or to add more variables. Let’s write the script /home/baeldung/preload.sh which loads /etc/profile, ~/.bash_profile, ~/.bashrc, and exports one more variable:

#!/bin/bash

. /etc/profile
. ~/.bash_profile
. ~/.bashrc
export LEARNING_FROM=baeldung

Now, we’ll modify the crontab file to use /home/baeldung/preload.sh:

* * * * * BASH_ENV=/home/baeldung/preload.sh /home/baeldung/print_envs.sh

After waiting one minute, we get the result:

$ wc -l /tmp/print_envs_result 
41 /tmp/print_envs_result 
$ grep LEARNING_FROM /tmp/print_envs_result 
LEARNING_FROM=baeldung

We can notice, we now have 41 environment variables. Additionally, we have the variable LEARNING_FROM with the value “baeldung“.

3. Wrapping the Job With Bash

Let’s suppose we have this crontab file:

* * * * * printenv > /tmp/print_envs_result

As printenv is not a bash script, we can’t use BASH_ENV to load the environment variables. However, we can wrap it with bash. We do this by prepending bash -c to the job and enclosing the job inside double-quotes. When we use the -c parameter, bash reads the command from the parameters and executes it.

Let’s use BASH_ENV after adding bash -c to the job:

* * * * * BASH_ENV=/etc/profile bash -c "printenv > /tmp/print_envs_result"

After cron runs the job, we can see printenv loaded all the environment variables from /etc/profile:

$ wc -l /tmp/print_envs_result
38 /tmp/print_envs_result
$ grep PS1= /tmp/print_envs_result
PS1=\u@\h:\w\$

If we need to add more environment variables or to load more files, we can write a new script to include the files we need. Now, we have two options. We can load the new script using BASH_ENV, just as we did in the previous section. Or instead, we can move the original job from the crontab file to the end of the new script.

Let’s wrap the job in a new script called /home/baeldung/wrap_printenv.sh:

#!/bin/bash

. /etc/profile
. ~/.bash_profile
. ~/.bashrc
export LEARNING_FROM=baeldung

#now, we run the original job
printenv > /tmp/print_envs_result

And finally, we change the crontab file to run the new script:

* * * * * /home/baeldung/wrap_printenv.sh

Similarly to the previous section, we can see the environment variables in the result:

$ wc -l /tmp/print_envs_result 
41 /tmp/print_envs_result 
$ grep LEARNING_FROM /tmp/print_envs_result 
LEARNING_FROM=baeldung

4. Running the Job With a Login Shell

When we run bash as a login shell, it loads the files /etc/profile, ~/.bash_pofile, ~/.bash_login, and ~/.profile. If we want to emulate this from a cron job, we can run a login shell to execute the job. This way, bash will run all the login scripts, loading the environment variables from those files. To do this, we have to prepend the job with bash -l -c and enclosing the job inside double-quotes. When we use the -l parameter, we force bash to run as a login shell.

Let’s run the printenv example from the previous section with a login shell:

* * * * * bash -l -c "printenv > /tmp/print_envs_result"

As this is still a non-interactive shell, bash doesn’t load the ~/.bashrc script. If we need it, we can overcome this by also using BASH_ENV.

Let’s use it to load ~/.bashrc along with the login shell:

* * * * * BASH_ENV=~/.bashrc bash -l -c "printenv > /tmp/print_envs_result"

Now, we wait for cron to run the job and see bash loaded several environment variables:

$ wc -l /tmp/print_envs_result
41 /tmp/print_envs_result

5. Setting Each Variable in the crontab File

Similar to the BASH_ENV method mentioned before, we can set any variable writing name=value before the command. If we specify more than one variable, we have to space them with whitespaces in between.

Let’s set LEARNING_FROM and LANG to run the print_envs.sh job:

* * * * * LEARNING_FROM=baeldung LANG=es_US /home/baeldung/print_envs.sh

And after one minute, we can see the script loaded those variables:

$ grep -E 'LANG|LEARNING_FROM' /tmp/print_envs_result 
LEARNING_FROM=baeldung
LANG=en_US

We can notice, if we need to set a lot of variables, we’ll end up with a very long line. If we do so, the crontab file may be difficult to understand.

Some Linux distributions, like Fedora and Arch, provide the cronie implementation of cron. This implementation allows us to set environmental variables in the crontab file for all jobs. We do this by writing each environment variable in one line at a time, without any job in it.

Let’s define LEARNING_FROM and LANG for all jobs:

LEARNING_FROM=baeldung
LANG=es_US
* * * * * /home/baeldung/print_envs.sh

And as we see, the script loads those variables:

$ grep -E 'LANG|LEARNING_FROM' /tmp/print_envs_result 
LEARNING_FROM=baeldung
LANG=en_US

6. Conclusion

In this tutorial, we saw different methods to load environment variables in a cron job.

First, we saw how to use the BASH_ENV variable to load a script before the job. This allowed us to load environment variables from other files, like /etc/profile.

Then, we saw we can wrap a job inside a new script where we set and loaded all the environment variables we needed before running the original job.

Finally, we learned we can set environment variables one by one, writing them directly in the crontab file.

Comments are closed on this article!