在备份脚本中保留 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
中除 2015
、2016
或 2017
.
中的任何文件
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/backup
将 rm -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
这是如何运作的
生成文件名列表 star 带有“2”,仅在 /home/backup/
下
按字母顺序对列表进行倒序排列。
使用AWK过滤列表中的行数。 NR 指定反向排序的行数。您可以将 3 更改为您想要保留的行数。因此,如果您只想要最近两年的数据,请将 3 更改为 2。如果要保留最新的 10 个,请设为 "NR>10".
将结果列表附加到命令 "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 也被发送删除,这将是一场灾难。这是我在上面试图弄清楚的一个非常小的区别。我已经删除了之前的答案并用这个替换它。
我在 /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
中除 2015
、2016
或 2017
.
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/backup
将rm -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
这是如何运作的
生成文件名列表 star 带有“2”,仅在 /home/backup/
下按字母顺序对列表进行倒序排列。
使用AWK过滤列表中的行数。 NR 指定反向排序的行数。您可以将 3 更改为您想要保留的行数。因此,如果您只想要最近两年的数据,请将 3 更改为 2。如果要保留最新的 10 个,请设为 "NR>10".
将结果列表附加到命令 "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 也被发送删除,这将是一场灾难。这是我在上面试图弄清楚的一个非常小的区别。我已经删除了之前的答案并用这个替换它。