A backup script that works when you run it and does nothing at three in the morning is almost always PATH. cron reads neither .bashrc nor /etc/profile; it starts the job with a PATH of /usr/bin:/bin and very little else, so anything installed under /usr/local/bin — which is most things installed by hand — is simply not found.
# find out exactly what the job sees, once
* * * * * env > /tmp/cron-env.txt
# HOME=/home/deploy
# PATH=/usr/bin:/bin
# SHELL=/bin/sh
# LOGNAME=deploy
# so: declare both at the top of the crontab, and use absolute paths anyway
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
[email protected]
30 3 * * * /usr/local/bin/wp --path=/var/www/app db export -
| gzip > /backups/db-$(date +%F).sql.gz 2>> /var/log/backup.log
SHELL=/bin/sh is the other half of the trap on Debian and Ubuntu, where /bin/sh is dash — so [[ ]], source and arrays fail with a syntax error in a script that runs perfectly from your login shell. The % is a third: cron treats it as a newline, so a date format string has to be escaped as %F or the command is truncated at that point. Declaring PATH in the crontab is the cheapest general answer; absolute paths in the command are the honest one, because they survive the job being moved to another user or into /etc/cron.d. The reason none of this ever surfaces is MAILTO — cron mails the output somewhere, and on a box with no working mail transport it goes nowhere. Redirect to a file and the error is on disk the first morning instead of the third week.