1

I am using Rsnapshot for backups (Linux CentOS 6).

Here is my /etc/cron.d/rsnapshot:

30 11 * * * root    /usr/bin/rsnapshot nowandthen > /backups/rsnapshot_cron.txt 2>&1
15 11 * * 4 root    /usr/bin/rsnapshot weekly > /backups/rsnapshot_cron.txt 2>&1
00 11 24-31 * 4 root    /usr/bin/rsnapshot monthly > /backups/rsnapshot_cron.txt 2>&1

Monthly backup was intended to be executed every last Thursday in any month.

However, monthly backup executed today, Thursday, 2016-Feb-18 at 11:00. Today is not last Thursday in a month.

What's wrong with my crontab?

Danijel
  • 685
  • 11
  • 25
  • what do you see in your logs? – Jakuje Feb 18 '16 at 13:04
  • Your crontab appears to be correct. Do you have the correct date on your computer? What's the output of `date`? Anything relevant in from `grep CRON /var/log/syslog`? – agtoever Feb 18 '16 at 13:22
  • I can't explain why it ran on 18th, but remember there are several `crontab` files: as well as `/etc` entries there is one for each user, including `root`. Regardless, your script will not do what you want: if the last day of a 31-day month is a Thursday it will run on both 24th and 31st; if the last day of February is a Wednesday it won't run at all. – AFH Feb 18 '16 at 13:42

1 Answers1

3

According to this site, your string means “At 11:00 on the 24, 25, 26, 27, 28, 29, 30 and 31st of every month and every Thu.” (my emphasis). If the site is correct this would explain why it ran on 18th.

The example entry in man 5 crontab to run on 2nd Saturday is:

0 4 8-14 * *    test $(date +\%u) -eq 6 && echo "2nd Saturday"

(ie run every day of the second week and check for the week day as part of the command) - this supports the view that the week day is an additional, alternative filter, not a further qualification, though the manual page does not make it clear.

So in your case I would use:

00 11 * * 4 root test $(date -d @$((`date +\%s`+604800)) +\%m) -ne $(date +\%m) && /usr/bin/rsnapshot monthly > /backups/rsnapshot_cron.txt 2>&1

Check if your date supports -d 'next Thursday': if so you can use the rather simpler:

00 11 * * 4 root test $(date -d 'next Thu' +\%m) -ne $(date +\%m) && /usr/bin/rsnapshot monthly > /backups/rsnapshot_cron.txt 2>&1

This runs every Thursday and checks if the date a week (604800 seconds) from now is in the same month: if not, it must be the last Thursday so the back-up command runs.

AFH
  • 17,300
  • 3
  • 32
  • 48
  • You will need to escape percent signs, like in the 2nd Saturday example. – tripleee Feb 18 '16 at 20:35
  • If you have GNU date, it supports `-d "next thursday" +%m` so you can skip one nested subcommand. – tripleee Feb 18 '16 at 20:38
  • @tripleee - I tested the command with `bash` on Ubuntu, and no escaping was necessary, though I didn't check it in `crontab`, because testing would be too difficult. I can imagine it would be necessary in a GNU/Windows environment, but I'll change my answer, as it can do no harm. Thanks for the "next Thursday" tip: it works on Ubuntu, so I'll incorporate it. – AFH Feb 18 '16 at 22:49
  • The escaping of percent signs is a requirement which is specific to `crontab` syntax; so yes, it would work at the prompt without escaping. – tripleee Feb 19 '16 at 05:41
  • No time to test... waiting for the next Thursday. :) – Danijel Feb 19 '16 at 10:29
  • @tripleee - OK, thanks. I've now found the discussion of percent signs in the manual page. I had erroneously assumed than the command would be passed verbatim to a shell. We live and learn. – AFH Feb 19 '16 at 13:37
  • @Danijel - I suggest you put in an extra, dummy command (eg to echo to a file) with the same time and test syntax, but specifying a time in the immediate future. This will make sure it _doesn't_ run unexpectedly. You'll have to wait until next Tuesday to make sure it _does_ run when expected. However, if you use the long form, having made sure it doesn't run today, change the seconds offset to `+604800*2` and it should then run. This will be a good check before next week comes round. Note my edit to escape the percent signs, after @tripleee's comments. – AFH Feb 19 '16 at 13:51
  • Oh and actually the `$((...))` stuff is a Bash extension, so is not strictly permitted in `crontab`, which runs `sh` always. You can say `bash -c '...your script...'` or hope that `sh` is a `bash` which is not too strict about POSIX mode. – tripleee Feb 19 '16 at 15:32
  • @tripleee - I did actually try it in `sh`, though on Ubuntu it is linked to `bash`, but it runs with `sh` syntax. It's also documented in the `sh` manual, though it is Korn- not Bourne-compatible. I did wonder about suggesting putting the test into a script which returns the result of the test: that could then be preceded by `#!/bin/bash`. Alternatively, it is possible to set the `SHELL` environment variable prior to launching `cron` so as to specify which shell to use. – AFH Feb 19 '16 at 15:58