0

I want to make a backup script which would do a full back up once every week and otherwise incremental backup every day.

How would I go about setting up a condition depending on the number of days have gone? So if a week has gone, it would execute a full back up, otherwise it would override the last incremental backup.

That same skript I would than add to /etc/cron.weekly and /etc/cron.daily

4 Answers 4

1

You could do something like this:

day_of_week=$(date '+%w')
# or with recent bash
printf -v day_of_week '%(%w)T' -1

then

case $day_of_week in
    0) do_full_backup ;;
    *) do_incremental_backup ;;
esac

Then, you run the backup script every day and it can figure out if it should do full or incremental.

1
  • Thank you! That's exactly what I was looking for! Commented Aug 3, 2022 at 15:18
0

How would I go about setting up a condition depending on the number of days have gone?

If you want to check the actual number of days that have passed since the last full backup, instead of just the current day, you'll need to save the timestamp of the last full backup and check that.

Possibly simplest would be to just check the unix timestamp, i.e. number of seconds that have passed:

#!/bin/bash
file=last_full
elapsed=999999999
min_interval=$((6*86400 + 12*3600))   # 6 d + 12 h
now=$(date +%s)
if [[ -f "$file" ]]; then
    elapsed=$(( now - $(< "$file") ))
fi

if (( elapsed > min_interval )); then
    echo run full backup...
    echo "$now" > "$file"
else
    echo run incremental backup...
fi

Or convert the number of seconds into days first, with e.g. days=$(( elapsed / 86400 )) or with rounding days_rounded=$(( (elapsed + 86400/2) / 86400 )).

This way it won't matter if the script gets missed one Sunday, it'll then just run the next full backup the next time it runs, e.g. on Monday. The downside is that all the next full backups will then also shift to Mondays. Though you could bypass that by also checking the weekday, e.g.:

if (( elapsed > min_interval )) || [[ $(date +%w) = 0 ]]; then
    echo run full backup...
    ...
fi

(The point of the 6.5 day cutoff is to avoid issues if the script's execution gets delayed slightly due to system load on one day, causing the next interval to be a few seconds short of full days.)

That same skript I would than add to /etc/cron.weekly and /etc/cron.daily

If you run it from both, it'll run twice on Sundays. (Or whatever the day cron.weekly runs is anyway.) If the script itself checks which one it needs to do, you can just run it from cron.daily.

An alternative to using cron.daily and cron.weekly would be to make two lines in crontab:

0 4 * * 0   /path/to/mybackup.sh full
0 4 * * 1-6 /path/to/mybackup.sh incremental

And then check the first command line argument $1 in the script. This would avoid the double run on Sundays, but would have the same problem as before: missing a Sunday run would miss the full backup for the week.

0

My backups script does something similar. Earlier it sets up two global variables: dayno which is the "first" .. "fourth" week of the month, and dayname which is "Sunday" .. "Saturday". The following function then returns 0 for a level 0 dump, 1 for a level 1 dump when just the day of week matches, and 2 for a level 2 dump for other days. The relevant function is:

#       get_level calculates the appropriate level for the dump from
#       the day or the week and the day of the month.
#
function get_level {
        put_trace "$trace" "$this_shell" "Calculating level"
        day_of_week=$(date $today +%A)
        put_debug "$debug" "Today is $day_of_week $(date $today +%d)"
        if [[ "$dayname" == "${day_of_week,,}" ]]       # Force to lowercase
        then
                case $(date $today +%d) in
                    01|02|03|04|05|06|07)       week="first" ;;
                    08|09|10|11|12|13|14)       week="second" ;;
                    15|16|17|18|19|20|21)       week="third" ;;
                    *)                          week="fourth" ;;
                esac
                if [[ "$week" == "$dayno" ]]
                then
                        echo 0
                else
                        echo 1
                fi
        else
                echo 2
        fi
}

Ignore the put_trace and put_debug lines, you'd need to have my supporting bash library to use them.

date $today +%A returns the day name ($today can be altered from the command line, just read it as the current date). If the day of the week matches when level 1 and level 0 backups are to be done, then determine which week of the month it is, otherwise return level 2. The case statement may be crude, but is obvious and works!

Feel free to copy as much or as little as you want. The script this is part of has been running on various machines for about 3 years and the resulting dumps have been restored on occasions, so it works.

0

I'd set it up this way:

if [ "$(date '+%w')" -eq 0 ]; then
    backup_full
else
    backup_incremental
fi

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.