213

I want to create a log file for a cron script that has the current hour in the log file name. This is the command I tried to use:

0 * * * * echo hello >> ~/cron-logs/hourly/test`date "+%d"`.log

Unfortunately I get this message when that runs:

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

I have tried escaping the date part in various ways, but without much luck. Is it possible to make this happen in-line in a crontab file or do I need to create a shell script to do this?

0

6 Answers 6

305

Short answer:

Escape the % as \%:

0 * * * * echo hello >> ~/cron-logs/hourly/"test$(date +\%d).log"

This also uses $(...) instead of the deprecated `...` syntax for command substitution and quotes the expansion of said command substitution.

Long answer:

The error message suggests that the shell which executes your command doesn't see the second backtick character:

/bin/sh: -c: line 0: unexpected EOF while looking for matching '`'

This is also confirmed by the second error message you received when you tried one of the other answers:

/bin/sh: -c: line 0: unexpected EOF while looking for matching ')'

The crontab manpage confirms that the command is read only up to the first unescaped % sign:

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 cronfile. 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.

2
  • Why did they implement this behaviour for the percent sign?
    – rubo77
    Jun 7, 2022 at 0:53
  • @rubo77 Some commands can accept input from stdin, so this behaviour of % might be useful when calling such commands. I have never used it myself, but perhaps you might want to pass "y" over standard input, to answer a yes/no confirmation prompt from the command, or pass some commands to an ftp client, to initiate the transfer of a file. Sep 8, 2023 at 9:32
25

If you would like to make the date formatting string as a variable (to avoid duplicating the whole string), DO NOT escape % and DO NOT put it in $()

For example, while declare the string, just write:

DATEVAR="date +%Y%m%d_%H%M%S"

Then, write cron statement with $($VARIABLE_NAME) like this:

* * * * * /bin/echo $($DATEVAR) >> /tmp/crontab.log

Thanks to cyberx86, her/his answer at ServerFault might be more completed:

2
  • This answer has issues with quoting, and it's unclear where to set the DATEVAR variable and how to do it in such a way that it support e.g. format string containing spaces.
    – Kusalananda
    Jan 11, 2021 at 9:47
  • 1
    Quoting is fixed. You put the definition in the head of your crontab file
    – rubo77
    Jun 7, 2022 at 0:57
9

You can also put your commands into a shell file and then execute the shell file with cron.

jobs.sh

echo hello >> ~/cron-logs/hourly/test`date "+%d"`.log

cron

0 * * * * sh jobs.sh
2
  • This is generally a good idea, but does not help where output must be redirected to a datestamped logfile from the crontab itself. If the output redirect is done inside the shell script, cron still tries to capture the output and email it to you, causing this problem: askubuntu.com/questions/222512/… (hint: you DO NOT need to install an MTA, but you will need to move the output redirect into the crontab command, even if this is not as pretty as you might like) Feb 13, 2023 at 4:11
  • ... on the other hand, it looks like you can still redirect to >>dev/null 2>&1 on the job in crontab, and then do different redirects on lines inside the shell script Feb 13, 2023 at 14:37
5

In cron, you can use this simple syntax:

*/15 01-09 * * * sh /script.sh >> /home/username/cron_$(date -d"-0 days" +\%Y\%m\%d).log 2>&1
2
  • 1
    Output date format will retrun like cron_20180123.log Jan 24, 2018 at 13:51
  • 7
    (1) What are you saying that hasn’t already been said by the accepted answer?   (2) Your answer is much more complicated than the question.  For example, you added the -d option, which is not used in the question (and you did not explain it).  How do you justify calling this “simple syntax”? Dec 23, 2018 at 6:27
4

A basic solution:

  • use $() for executing date command and return output
  • format datetime to UTC, escape the % character with \
  • add 2>&1 at the end for streaming both stdout and stderr into that log file

Example:

* * * * * echo "Test crontab log" > /tmp/crontab.log.$(date --utc +\%Y\%m\%d_\%H\%M\%SZ) 2>&1

Output:

ls -lh /tmp | grep log

-rw-rw-r-- 1 ubuntu  ubuntu    17 May  4 05:06 crontab.log.20190504_050601Z
-rw-rw-r-- 1 ubuntu  ubuntu    17 May  4 05:07 crontab.log.20190504_050701Z
0

This worked for me:

0 5 * * 3 /data/script.sh > /data/script_`date +\%y\%m\%d`.log 2>&1
4
  • 5
    What are you saying that hasn’t already been said by the accepted answer? Are you saying that it works better without quotes than it does with quotes? (Hint: that’s very unlikely.) Dec 23, 2018 at 6:27
  • The accepted answer simply doesn't work for me. This one does. Dec 23, 2018 at 8:44
  • Perhaps it’s the 2>&1 that’s significant here (and not featured in other answers), rather than the quotes. Oct 20, 2022 at 8:56
  • Using 2>&1 is (almost always) a good call for logging, and probably does solve whatever problem was going on in /data/script.sh, but it is only tangential to the OP's question about using the date command in cron Feb 13, 2023 at 4:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .