What's wrong with these two cron jobs?

There are three common causes for cron job commands to behave differently compared to commands typed directly into an interactive shell, in rough order of commonness:

  • Cron provides a limited environment, e.g., a minimal $PATH, and other expected variables missing.
  • Cron invokes /bin/sh by default, whereas you may be using some other shell interactively.
  • Cron treats the % character specially (it is turned into a newline in the command).
  • Cron doesn't provide a terminal or graphical environment.

You must precede all % characters with a \ in a crontab file, which tells cron to just put a percent in the command. Remember that when you use the date command in a cron job.

55  8   *   *   3   /usr/bin/php /home/mark/dev/processes/customClient/events.php > "/home/mark/dev/processes/customClient/events-$(date +\%Y-\%m-\%d --date='last Wednesday')-$(date +\%Y-\%m-\%d).csv"
0   9   *   *   3   /usr/bin/echo 'The csv for last week, trying my hand at automatiging this' | /usr/bin/mutt <emailaddress> -s "Events from $(date +\%Y-\%m-\%d --date='last Wednesday')-$(date +\%Y-\%m-\%d)" -a "/home/mark/dev/processes/customClient/events-$(date +\%Y-\%m-\%d --date='last Wednesday')-$(date +\%Y-\%m-\%d).csv"

I also fixed some quoting problems:

  • This wasn't causing you problems other than with legibility, but you shouldn't use backticks for command substitution. Use $(…) instead: its parsing rules are simpler.
  • Always use double quotes around variable and command substitutions: "$somevariable", "$(somecommand)". Here the lack of quotes was harmless because the date command never returned any special character for the formats you used, but you have to carefully remember which characters are special and check this every time you leave a substitution unquoted. Keep it simple, always use double quotes unless you want field splitting and filename generation to happen on the result.
  • You had some single quotes preventing expansion around some command substitutions. Use double quotes instead.

I strongly recommend putting any non-trivial cron jobs into their own shell script file, for many reasons:

  • Easier to debug: you can just run the script instead of copy pasting a long line, and with the right shebang line, it behaves much more predictably than if you had the same commands directly in the crontab
  • Easier to read: no need to make it a 200+ character one-liner, you can format it nicely so it's easy to read and understand for everyone
  • Add the script to version control