2

I have a Cron Job running quarterly on every first Sunday of the Month:

0 0 1-7 3,6,9,12 * [ "$(date '+\%a')" == "Sun" ] && /script.sh

Now I want to install it automatically using echo like:

(crontab -l ; echo "0 0 1-7 3,6,9,12 * [ "$(date '+\%a')" == "Sun" ] && /script.sh") | crontab -

while escaping \"Sun"\ works fine I can't escape "$(date '+\%a')" as this is a mix of single and double quotes with \ within double quoted echo command.

DisplayName
  • 479
  • 2
  • 7
  • 20

2 Answers2

2

You don't need to use crazy escaping. Use [[ ... ]] provided by bash instead of old (and error prone) [ ... ]:

So use:

0 0 1-7 3,6,9,12 * [[ $(date +\%a) == Sun ]] && /script.sh

And to install it automatically use:

(crontab -l ; echo '0 0 1-7 3,6,9,12 * [[ $(date +\%a) == Sun ]] && /script.sh') | crontab -

PS: Make sure to set SHELL=/bin/bash in the crontab file before this line.

DevSolar
  • 67,862
  • 21
  • 134
  • 209
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 2
    Since `[[ ]]` isn't available in all shells, if you're going to use this solution you should set `SHELL=/bin/bash` in the crontab file *before* this line. Also, you still need to escape the `%`, so cron doesn't treat it as a line break. – Gordon Davisson Apr 13 '22 at 09:54
  • Thanks @GordonDavisson, very good points. I have edited. – anubhava Apr 13 '22 at 09:59
1

You could use a here document to avoid having to quote the crontab entry:

read -r crontab_entry <<'END_CRONTAB_ENTRY'
0 0 1-7 3,6,9,12 * [ "$(date '+\%a')" == "Sun" ] && /script.sh
END_CRONTAB_ENTRY

(crontab -l; printf '%s\n' "$crontab_entry") | crontab -
  • See the accepted, and excellent, answer to Why is printf better than echo? for an explanation of why I used printf instead of echo to output the crontab entry.
  • Note that date '+\%a' produces output like \Sun (for some versions of the date program). You probably want date '+%a'.
    (Update: the comment by Gordon Davisson explains that the backslash in date '+\%a' is necessary because the command is in a crontab.)
  • Note also that the string produced by the %a date format depends on the locale. It could be something other than Sun for Sunday. It's safer to use a numeric day (e.g. [ "$(date '+%w')" -eq 0 ]).
  • Finally, note that using == with [...] is not portable between shells. Use = unless you are sure that the crontab entries will only be run with Bash.
pjh
  • 6,388
  • 2
  • 16
  • 17
  • Both `date '+%a'` and `date '+\%a'` produce `Wed` for me in Debian (5.0.3(1)) and Ubuntu (5.0.17(1)) – DisplayName Apr 13 '22 at 11:46
  • @SynRomana, `date '+\%a'` currently outputs `\Wed` for me. I guess it's due to having a different version of the `date` program. – pjh Apr 13 '22 at 12:02
  • 1
    The escape before `%` is crontab syntax, and will not be executed as part of the actual `date` command. See ["How is `%` special in crontab?"](https://stackoverflow.com/questions/5277508/how-is-special-in-crontab) – Gordon Davisson Apr 13 '22 at 16:57