7

How to do this with cron?

  • Today: cp * ~/destination.0
  • Tomorrow: cp * ~/destination.1
  • Next day: cp * ~/destination.0
  • Next day: cp * ~/destination.1

...and so on.

Any help would be greatly appreciated!

1
  • Yes, I will use rsync, cp was just for the example
    – Stefan
    Dec 2, 2017 at 15:15

4 Answers 4

6

One Liner:

0 0 * * * cp /path/to/* /path/to/destination.$(( $(date -d $(date +%F) +%s)/(3600*24) % 2))

Explanation:

$(( $(date -d 0:00 +%s)/(3600*24) % 2))
  • will return timestamp in seconds (+%s) of today at 0:00 (-d 0:00).
  • Divided by (3600*24) will return number of days from unix epoch.
  • %2 will return 0 or 1 for odd or even days since start of unix epoch.
4
  • % 2 is simple a modulo operation, which returns 1 if the days number given to it is odd and 0 if it is even.
    – Videonauth
    Dec 1, 2017 at 13:49
  • +1 for the solution using the seconds since 1970-01-01 00:00:00 UTC option. On this way you don't have to think about the 30/31 days/months problem of other attempts here
    – derHugo
    Dec 1, 2017 at 14:20
  • @RoVo that's exactly what I've looked for because of the two odd days 31 and 1 ! Very smart!
    – Stefan
    Dec 2, 2017 at 15:20
  • True. I updatet the answer.
    – pLumo
    Dec 2, 2017 at 17:18
2

I agree with the "run the cronjob daily, switch directories in the script" answers, but I'd do it like this:

#!/bin/bash 
# use hidden link
last=$HOME/.last_destination
#
declare -a dirs
dirs[0]="destination.0"
dirs[1]="destination.1"
#
target=
#
# If $last is a link, it points to the last used directory. Otherwise,
# initialize it and use $HOME/destination.0
if [[ -L "$last" ]] ; then
    # get the name of the linked dir
    old="$(stat  --printf="%N" "$last" | cut -d\' -f4)"
    if [[ "$old" == "${dirs[0]}" ]] ; then
        target="${dirs[1]}"
    else
        target="${dirs[0]}"
    fi
else
    # "$last" is not a link - first time initialization
    target="${dirs[0]}"
fi
# now, with $target set, point the $last link at $target, for next time
rm "$last"
ln -s "$target" "$last"
#
# debugging printouts - remove in real life
echo "$target"
ls -l "$last"
2

If it would be OK to write to ~/destination.0 on even dates and ~/destination.1 on odd dates, the following crontab line should work. It starts the backup at midnight (0 min, 0 hour, the two first items on the line),

0 0 * * * echo cd dir2copy;dtmp=$(( $(/bin/date '+%d') % 2 ));echo /bin/cp * ~/destination."$dtmp"

See this link for an explanation of the crontab syntax,

Scheduling Tasks with Cron Jobs

Test the command part of the line in a terminal window,

echo cd dir2copy;dtmp=$(( $(/bin/date '+%d') % 2 ));echo /bin/cp * ~/destination."$dtmp"

and when it works, you can replace cd dir2copy with cd to-the-actual-directory-you-want-to-copy, replace ~ with /home/your-home-directory and remove the two echo words to make it do the real job.

Test it again, and then modify the crontab line. (The environment in crontab is such that you may need explicit full paths to programs, directories and data files.)


/bin/date '+%d' finds the day of month and % is the remaindering operation, that produces a 0 or 1, which is appended at the end of the command line.

You may prefer /bin/date '+%j', which finds the day of year, for example today, Dec 1, is day #335.

5
  • will not alternate between day 365 and 1.
    – pLumo
    Dec 1, 2017 at 14:17
  • 1
    Yes, you are right @RoVo . I noticed, that you have fixed that, and I will upvote your answer :-) You have spent more effort than I to make things work exactly according to the specification in the question. It would be OK for me at new year, that the alternation would skip. My computer might be turned off anyway ;-)
    – sudodus
    Dec 1, 2017 at 14:24
  • True, but I started with the same problem ... +%w: fuck the week has an odd number of days... then +%d, then +%j... then ... shit I'm fucked ...
    – pLumo
    Dec 1, 2017 at 14:26
  • Anyways after a leap year +%j will work correctly on new year ^^
    – pLumo
    Dec 1, 2017 at 14:29
  • not if the leap year is %100 :P
    – derHugo
    Dec 1, 2017 at 14:31
0

Run this script daily from cron:

#! /bin/sh
set -e
cp * ~/destination.0
mv ~/destination.0 ~/destination.last
mv ~/destination.1 ~/destination.0
mv ~/destination.last ~/destination.0
3
  • you never write anything to ~/destination.1...
    – derHugo
    Dec 1, 2017 at 13:55
  • Right, there's a bug in my (untested) script, the last line should rename *.last to *.1 instead of *.0... and in the meantime I've seen better solutions involving modulo 2 computations
    – Luc Moreau
    Dec 1, 2017 at 14:23
  • Even than you would every day copy to destination.1 and have destination.0 as backup .. but actualy not alternating between two destinations.
    – derHugo
    Dec 1, 2017 at 14:29

You must log in to answer this question.

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