在备份脚本中保留 n 个最近的目录

Retaining n most recent directories in a backup script

我在 /home/backup/ 中有目录存储年度备份。在备份文件夹中,我们有这些目录:

/home/backup/2012
/home/backup/2013
/home/backup/2014
/home/backup/2015
/home/backup/2016
/home/backup/2017

而且每年都要清理数据,只保留最近三年的备份。

在上面的情况下,我必须删除:

/home/backup/2012
/home/backup/2013
/home/backup/2014

查找要删除的目录的最佳方法是什么?我有这个,但它不起作用:

find /home/ecentrix/recording/ -maxdepth 1 -mindepth 1 -type d -ctime +1095 -exec rm -rf {} \;

你们有别的想法吗?

如果你想删除目录,你应该输入以下命令

sudo rm -r [folder name]
#in your case it will be 
sudo rm -r /home/backup/2012
sudo rm -r /home/backup/2013
sudo rm -r /home/backup/2014

由于您的目录具有明确定义的整数名称,我将使用 bash 来计算适当的目标:

mkdir -p backup/201{2..7} # just for testing

cd backup
rm -fr $(seq 2012 $(( $(date +"%Y") - 3)))

seq 生成一个从 2012 年到当年减 3 的数字列表,然后将其传递给 rm 进行爆破。

解决方案

# Check if extended globbing is on
shopt extglob

# If extended globbing is off, run this line
shopt -s extglob

# Remove all files except 2015, 2016, and 2017
rm -r -i /home/backup/!(2015|2016|2017)

# Turn off extended globbing (optional)
shop -u extglob

说明

shopt -s extglob 允许您匹配除 !(...) 内的文件之外的任何文件。因此,该行意味着删除 /home/backup 中除 201520162017.

中的任何文件

rm -r -i ... 中的 -i 标志允许您以交互方式确认每个文件的删除。如果您希望自动删除文件,请删除 -i

动态日期

此解决方案适用于自动化(例如 cron 作业)

# Number of latest years to keep
LATEST_YEARS=3

# Get the current year
current_year=$(date '+%Y')

# Get the first/earliest year to keep
first_year=$(( current_year - $(($LATEST_YEARS - 1)) ))

# Turn on extended globbing
shopt -s extglob

# Store years to keep in an array
keep_years=( $(seq $first_year $current_year) )

# Specify files to keep
rm -r /home/backup/!(${keep_years[0]}|${keep_years[1]}|${keep_years[2]})

NOTE: ALL FILES IN BACKUP DIRECTORY WILL BE REMOVED EXCEPT LAST 3 YEARS

这是一种方法。

更新答案。

[dev]$ find backup/*  | grep -vE "$(date '+%Y')|$(date +%Y --date='1 year ago')|$(date +%Y --date='2 year ago')" | xargs  rm -rfv

removed directory: ‘backup/2012’
removed directory: ‘backup/2013’
removed directory: ‘backup/2014’

更通用的解决方案

我觉得最好是按降序遍历目录,然后删除第三个之后的目录。这样,当脚本一次又一次地 运行 时,就没有丢失目录的危险:

#!/bin/bash
backups_to_keep=3
count=0
cd /home/backup
while read -d '' -r dir; do
  [[ -d "$dir" ]]                || continue  # skip if not directory
  ((++count <= backups_to_keep)) && continue  # skip if we are within retaining territory
  echo "Removing old backup directory '$dir'" # it is good to log what was cleaned up
  echo rm -rf -- "$dir"
done < <(find . -maxdepth 1 -name '[2-9][0-9][0-9][0-9]' -type d -print0 | sort -nrz)

测试后删除rm -rf前的echo。对于您的示例,它给出以下输出:

rm -rf -- ./2014
rm -rf -- ./2013
rm -rf -- ./2012
  • cd /home/backuprm -rf 限制在该目录以提高安全性
  • find . -maxdepth 1 -name '[2-9][0-9][0-9][0-9]' -type d 给出匹配 glob
  • 的顶级目录
  • sort -nrz 确保较新的目录优先,-z 处理 find ... -print0
  • 的空终止输出
  • 此解决方案不会对年份进行硬编码 - 它只是假设要删除的目录以数字排序的方式命名
  • 它对备份目录中存在的任何其他文件或目录具有弹性
  • 如果脚本是 运行 一次又一次
  • 则没有副作用
  • 这可以轻松扩展以支持备份目录的不同命名约定 - 只需更改 glob 表达式

考虑一下:

find /home/backup/2* -maxdepth 1 | sort -r | awk "NR>3" | xargs rm -rf

这是如何运作的

  1. 生成文件名列表 star 带有“2”,仅在 /home/backup/

  2. 按字母顺序对列表进行倒序排列。

  3. 使用AWK过滤列表中的行数。 NR 指定反向排序的行数。您可以将 3 更改为您想要保留的行数。因此,如果您只想要最近两年的数据,请将 3 更改为 2。如果要保留最新的 10 个,请设为 "NR>10".

  4. 将结果列表附加到命令 "rm -rf"。

运行 作为专用用户,为了安全

这里的危险在于我建议 rm -rf。这是有风险的。如果出现问题,您可以删除要保留的内容。我通过仅由仅有权删除备份文件(且不能超出)的专用用户调用这些命令来减轻这种风险。

优点

这种方法的优点在于,当您将其放入 cron 作业中并且时间提前时,它将继续仅保留最新的几个目录。所以这个,我认为是你问题的一般解决方案。

示范[​​=55=]

为了对此进行测试,我创建了一个测试目录,其中包含您拥有的所有相同目录。我改变它只是为了看看最后会执行什么,所以我试过了:

find test01/2* -maxdepth 1 | sort -r | awk "NR>4" | xargs echo rm -rf

我使用 NR>4 而不是 NR>3(如您所愿),因为 NR>4 表明我们正在选择要从列表中删除的行数,因此不会删除.

这是我得到的:

上面的倒数第二个命令将最后阶段更改为 echo 它会做什么,而是实际执行。

我在脚本中有一个转储的粗略副本,因为我在我的一些服务器上使用它,你可以在这里查看它:https://github.com/docdawning/teenybackup

成功需要

此方法取决于 find 命令生成的任何内容的字母顺序。在我的例子中,我使用 ISO-8601 type dates,当它们按字母顺序排列时,它们完全适合于固有的日期排序。您的 YYYY 类型日期完全符合条件。

额外的安全

我建议您将备份更改为存储为 tar 存档。然后您可以将 rm -rf 更改为简单的 rm。这要安全得多,尽管不是万无一失的。无论如何,你真的应该 运行 作为一个专门的非特权用户(在我看来,你应该为任何调用删除的脚本做的)。

请注意,如果您tar将其与

搭配使用
find /home/backup

然后对 xargs 的调用将包括 /home/backup 本身,这将是一场灾难,因为它也会被删除。所以你必须在那个路径中搜索。而不是用下面的调用它会起作用:

find /home/backup/* 

我上面给出的 2* 只是某种程度上限制搜索操作的一种方式。

保修

None;这就是互联网。当心。大量测试以说服自己。另外,也许也可以做一些离线备份。


最后 - 我之前将此作为答案发布,但犯了一个致命错误,即表示基于 /home/backup 而不是 的查找命令/home/backup/*/home/backup/2*。这导致 /home/backup 也被发送删除,这将是一场灾难。这是我在上面试图弄清楚的一个非常小的区别。我已经删除了之前的答案并用这个替换它。