DisplayName
DisplayName

Reputation: 649

Escape double and single quotes in Bash

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.

Upvotes: 2

Views: 664

Answers (2)

pjh
pjh

Reputation: 8164

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.

Upvotes: 1

anubhava
anubhava

Reputation: 785481

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.

Upvotes: 2

Related Questions