When debugging cron jobs, the fundamental challenge lies in replicating the exact environment variables and user context that cron provides. Cron executes commands under a minimal environment - typically just HOME
, LOGNAME
, PATH
, and SHELL
are set. This differs significantly from your interactive shell environment.
The most reliable method is using env -i
to start with a clean environment and then set the minimal cron variables:
env -i \
PATH=/usr/bin:/bin \
SHELL=/bin/sh \
HOME=/home/youruser \
LOGNAME=youruser \
/path/to/your/script.sh
For more complex cases, capture cron's actual environment by modifying your script temporarily:
#!/bin/bash
# Debugging snippet to capture environment
env > /tmp/cron_environment.txt
# Rest of your script...
Then recreate it with:
set -a
. /tmp/cron_environment.txt
set +a
/path/to/your/script.sh
Combine environment simulation with output redirection for comprehensive testing:
env -i \
PATH=/usr/bin:/bin \
SHELL=/bin/sh \
HOME=/home/youruser \
LOGNAME=youruser \
/path/to/your/script.sh > /tmp/cron_debug.log 2>&1
On modern systems with systemd, you can create transient timers for testing:
systemd-run --user --on-calendar="*-*-* *:*:00" --unit=test-cron /path/to/your/script.sh
Then immediately trigger it with:
systemctl --user start test-cron.service
For advanced use cases, consider these specialized tools:
cronic
: A wrapper that makes cron output more manageablesupercronic
: A cron-compatible job runner designed for containersanacron
: For systems that aren't always running
Here's a full workflow example:
# 1. Create test script
cat <<'EOF' > /tmp/cron_test.sh
#!/bin/bash
echo "Cron test at $(date)" >> /tmp/cron_test.log
env >> /tmp/cron_test_env.log
EOF
chmod +x /tmp/cron_test.sh
# 2. Execute with cron environment
env -i \
PATH=/usr/bin:/bin \
SHELL=/bin/sh \
HOME=$HOME \
LOGNAME=$(whoami) \
/tmp/cron_test.sh
# 3. Examine output
cat /tmp/cron_test.log
cat /tmp/cron_test_env.log
Debugging cron jobs can be frustrating because they run in a different environment than your interactive shell. When a script works fine in your terminal but fails under cron, the usual suspects are:
- Different PATH environment variables
- Missing environment variables from your shell profile
- Different working directory
- Permission issues
The most accurate way to test is to become the cron user with the same environment:
sudo -u your_cron_user -i /path/to/your/script.sh
Or if you need to preserve the exact cron environment:
sudo -u your_cron_user env -i /path/to/your/script.sh
For even more accuracy, you can capture cron's environment first:
* * * * * env > /tmp/cronenv
wait 60 seconds
source /tmp/cronenv && /path/to/your/script.sh
Add these to your script for better debugging:
#!/bin/bash
# Log environment
env > /tmp/myscript_env.log
# Log current directory
echo "PWD: $PWD" >> /tmp/myscript_debug.log
# Redirect all output
exec >> /tmp/myscript_output.log 2>&1
# Your actual script starts here
...
On systemd systems, you can create an isolated environment similar to cron:
systemd-run --user --pty --same-dir --setenv=PATH=/usr/bin:/bin /path/to/your/script.sh
For Python scripts that fail under cron, try:
sudo -u your_cron_user env -i /usr/bin/python /path/to/script.py
Or with full environment:
sudo -u your_cron_user -i /usr/bin/python /path/to/script.py