Miskatonic University Press

Per cent signs in crontabs

unix

I learned something new—very minor, but still new—about cron jobs this week: if you use a per cent sign in the scheduled command, you need to escape it.

The documentation about cron can be hard to find. man cron shows “cron (8) - daemon to execute scheduled commands” (the 8, according to man man, meaning it’s a system administration command). But if you’re trying to figure out how to schedule a job, you don’t want to know about the daemon that takes care of the work. man crontab shows “crontab (1) - maintain crontab files for individual users”, which is the command to edit the crontab. The format of the crontab is found with man 5 crontab (5 meaning it’s to do with “file formats and conventions”), which shows “crontab (5) - tables for driving cron”.

I always forget how to schedule cron jobs beyond minute and hour, so pretty much every time I set up a new one I need to run man 5 crontab. I must have looked at it hundreds of times, but I never noticed about % until I ran into a problem.

I had something like this set up:

0 5 * * * YYYYMMDD=`date +%Y%m%d`; touch ~/tmp-$YYYYMMDD.txt

That creates a date-stamped file at 5 am every day. It works fine on the command line, but when cronned up I got these errors in email:

/bin/bash: -c: line 0: unexpected EOF while looking for matching ``'
/bin/bash: -c: line 1: syntax error: unexpected end of file

That didn’t make any sense, but this explained it:

The ``sixth’’ field (the rest of the line) specifies the command to be run. The entire command portion of the line, up to a newline or % character, will be executed by /bin/sh or by the shell specified in the SHELL variable of the crontab file. Percent-signs (%) in the command, unless escaped with backslash (\), will be changed into newline characters, and all data after the first % will be sent to the command as standard input. There is no way to split a single command line onto multiple lines, like the shell’s trailing “\”.

This works:

0 5 * * * YYYYMMDD=`date +\%Y\%m\%d`; touch ~/tmp-$YYYYMMDD.txt

I’ve never had occasion to use % to send STDIN to a command, or seen it used, but there must be some reason for it somewhere in Unix history.