每周(完整备份)和每天(增量)执行的备份脚本

每周(完整备份)和每天(增量)执行的备份脚本

我想制作一个备份脚本,每周进行一次完整备份,否则每天进行增量备份。

我将如何根据已经过去的天数设置条件?因此,如果一周过去了,它将执行完整备份,否则它将覆盖上次增量备份。

我会将相同的脚本添加到 /etc/cron.weekly 和 /etc/cron.daily

答案1

你可以这样做:

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

然后

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

然后,您每天运行备份脚本,它可以确定是否应该执行完整备份或增量备份。

答案2

我将如何根据已经过去的天数设置条件?

如果您想检查自上次完整备份以来已经过去的实际天数,而不仅仅是当天,则需要保存上次完整备份的时间戳并进行检查。

最简单的可能是只检查 unix 时间戳,即已经过去的秒数:

#!/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

days=$(( elapsed / 86400 ))或者首先使用例如或 四舍五入将秒数转换为天数days_rounded=$(( (elapsed + 86400/2) / 86400 ))

这样,如果脚本在某个周日丢失也没关系,它会在下次运行时(例如周一)运行下一个完整备份。缺点是接下来的所有完整备份也将转移到星期一。虽然你可以绕过它检查工作日,例如:

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

(6.5 天的截止时间是为了避免出现问题,如果脚本的执行由于某一天的系统负载而稍微延迟,导致下一个间隔比全天短几秒钟。)

我会将相同的脚本添加到 /etc/cron.weekly 和 /etc/cron.daily

如果您从两者都运行它,它将在周日运行两次。 (或者无论当天cron.weekly运行的是什么。)如果脚本本身检查它需要执行哪一项操作,您可以从 运行它cron.daily

使用cron.dailyand的另一种方法cron.weekly是在 中创建两行crontab

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

然后检查$1脚本中的第一个命令行参数。这将避免周日的双重运行,但会遇到与以前相同的问题:错过周日的运行将错过一周的完整备份。

答案3

我的备份脚本做了类似的事情。早些时候,它设置了两个全局变量:dayno哪个是该月的“第一”..“第四”周,dayname哪个是“星期日”..“星期六”。然后,以下函数返回00 级转储、1仅当星期几匹配时返回 1 级转储以及2其他日期的 2 级转储。相关函数是:

#       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
}

忽略put_traceput_debug行,您需要有我的支持 bash 库才能使用它们。

date $today +%A返回日期名称($today可以从命令行更改,只需将其读取为当前日期)。如果一周中的某一天与要完成级别 1 和级别 0 备份的时间相匹配,则确定是该月的哪一周,否则返回级别 2。 case 语句可能很粗糙,但很明显并且有效!

您可以根据需要随意复制。该脚本的一部分已经在各种机器上运行了大约 3 年,并且生成的转储有时已恢复,因此它可以工作。

答案4

我会这样设置:

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

相关内容