Why Crontab Jobs Don’t Inherit User Environment Variables (And How to Fix It)


2 views

When running scripts through cron, you might notice they behave differently than when executed manually - even when running as the same user. This happens because cron jobs don't inherit the full user environment that you get in an interactive shell session.

Cron executes commands in a minimal environment. The key differences are:

  • No shell initialization files (.bashrc, .profile) are loaded
  • Only a basic set of environment variables are set (PATH, HOME, LOGNAME)
  • No terminal or display environment variables

Here are several ways to ensure your cron jobs have the environment they need:

1. Source Your Profile

Modify your crontab entry to load the environment first:

0 2 */1 * * . /root/.profile; /aScript >aLog.log 2>&1

2. Environment Variable File

Create an env file and load it in your script:

# In crontab
0 2 */1 * * /aScript >aLog.log 2>&1

# In aScript
#!/bin/bash
source /path/to/env_vars
# Rest of your script

3. System-wide Environment

For system-wide environment variables, add them to /etc/environment:

# /etc/environment
MY_VAR="my_value"
export MY_VAR

To troubleshoot environment issues:

# Add this to your script temporarily
env > /tmp/cron_env.log

Compare this with your interactive environment:

env > /tmp/shell_env.log
diff /tmp/shell_env.log /tmp/cron_env.log
  • Always use absolute paths in cron jobs
  • Explicitly set critical environment variables in your script
  • Consider using a wrapper script that sets up the environment
  • For complex environments, use tools like envdir or direnv

Here's a robust wrapper script example:

#!/bin/bash
# cron_wrapper.sh

# Load environment
source /home/user/.profile

# Set additional variables
export PATH="/custom/path:$PATH"
export MY_APP_HOME="/opt/myapp"

# Run the actual script
/path/to/real_script.sh "$@"

Then in crontab:

0 2 */1 * * /path/to/cron_wrapper.sh >aLog.log 2>&1

When you schedule a cron job as root using crontab -e, you might expect it to run with the same environment variables as when you execute commands manually as root. However, cron jobs start with a minimal environment by default, which often causes scripts to fail or behave differently.

Cron executes commands in a restricted environment. The key differences include:

  • No shell initialization files (.bashrc, .bash_profile) are sourced
  • Only a minimal set of environment variables are set (PATH=/usr/bin:/bin)
  • No user-specific environment variables are loaded

Here are several effective approaches to solve this issue:

1. Source Environment Manually

Modify your cron entry to load the environment first:

0 2 */1 * * . /root/.bash_profile; /aScript >aLog.log 2>&1

2. Use a Wrapper Script

Create a wrapper script that sets up the environment:

#!/bin/bash
# /root/run_with_env.sh
source /root/.bashrc
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
/aScript >aLog.log 2>&1

Then call it from cron:

0 2 */1 * * /root/run_with_env.sh

3. Set Variables in Crontab

Define variables directly in crontab:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 2 */1 * * /aScript >aLog.log 2>&1

4. Use System-wide Environment

For system-wide environment variables, add them to /etc/environment:

MY_VAR="my_value"
  • Always test cron jobs by running them manually first
  • Use absolute paths in scripts called from cron
  • Log environment variables for debugging: env > /tmp/cron_env.log
  • Consider using systemd timers for complex jobs

To diagnose environment issues:

# Compare environments
env > /tmp/manual_env.log
# In crontab:
* * * * * env > /tmp/cron_env.log
diff /tmp/manual_env.log /tmp/cron_env.log

Remember that cron jobs run in a different context than interactive shells, so environment setup requires explicit configuration.