Fixing Scripts That Work Interactively but Fail Under cron
cron starts jobs with a small, non-interactive environment. Make paths, interpreters, working directories, credentials, and logging explicit instead of sourcing a full login shell.
A script that succeeds in a terminal but fails from cron is usually depending on invisible interactive state: a broader PATH, the current directory, a shell alias, an unlocked credential helper, or configuration loaded by a login shell.
Reproduce the smaller environment
Start by logging what cron actually sees, without writing secrets into a world-readable file:
SHELL=/bin/sh
PATH=/usr/local/bin:/usr/bin:/bin
[email protected]
15 2 * * * /home/alex/bin/backup.sh
Inside the script, send diagnostic output to a protected log or the scheduler’s mail facility. Record id, pwd, a sanitized environment, and resolved executable paths. Do not assume cron starts in the project directory.
Use an absolute interpreter and paths
The shebang controls which interpreter runs when the script is executed directly:
#!/bin/sh
set -eu
cd /home/alex/app || exit 1
/usr/bin/find ./exports -type f -mtime +14 -delete
An executable discovered through a version manager in .bashrc may not exist in cron’s PATH. Point at a stable installed interpreter or create a small wrapper that activates only the specific runtime environment the job needs.
Do not source an entire interactive profile as a shortcut
Interactive startup files often print output, assume a terminal, launch agents, define aliases, or return early for non-interactive shells. Sourcing them makes an automated job fragile. Put shared, non-interactive variables in a dedicated file with restrictive permissions, and source that file explicitly.
Check non-environment differences
Cron jobs have no controlling terminal, so password prompts and sudo interaction fail. Desktop keychains may be locked. Relative redirections land in unexpected locations. Percent characters have special meaning in some crontab implementations unless escaped. Daylight-saving changes can skip or duplicate wall-clock times.
Once fixed, test the exact cron entry or run the command with a deliberately minimal environment such as env -i HOME="$HOME" PATH=/usr/bin:/bin .... Success in a richly configured terminal is not the acceptance test for unattended automation.
Sources: