When Cron Does Not Share Your Shell
Why a command can succeed interactively but fail under cron, with a small wrapper pattern that makes paths and output explicit.

Photo: Unsplash.
A command that works in an interactive terminal may fail in cron because cron starts with a smaller environment. It may not load your shell profile, language manager, aliases, or the same PATH.
First, use absolute paths in the crontab:
SHELL=/bin/sh
PATH=/usr/local/bin:/usr/bin:/bin
15 2 * * * /srv/myapp/bin/nightly-backup >> /var/log/myapp-backup.log 2>&1
Put multi-step logic in a version-controlled script rather than squeezing it into one cron line:
#!/bin/sh
set -eu
PATH=/usr/local/bin:/usr/bin:/bin
export PATH
cd /srv/myapp
/usr/bin/date -Is
/usr/bin/env
./bin/backup --config /etc/myapp/backup.conf
Make it executable and test it as the same user that owns the cron entry:
chmod 750 /srv/myapp/bin/nightly-backup
sudo -u deploy /srv/myapp/bin/nightly-backup
To compare environments temporarily, capture cron’s environment to a file with restrictive permissions, inspect it, and remove it afterward. Do not leave secrets in debug output.
Also check the mundane failures:
- relative paths resolve from an unexpected working directory;
- a command exists only in an interactive version manager;
- the cron user cannot read a config file or write the destination;
- output is mailed or discarded instead of reaching the expected log;
- the server timezone differs from the schedule you had in mind.
The durable fix is not to make cron imitate your entire login shell. Give the job a small, explicit environment and make the wrapper independently testable.
