我有一个脚本可以删除比备份目录X = 21天更早的数据库转储:
DB_DUMP_DIR=/var/backups/dbs
RETENTION=$((21*24*60)) # 3 weeks
find ${DB_DUMP_DIR} -type f -mmin +${RETENTION} -delete
但是如果由于某种原因数据库转储作业暂时无法完成,所有转储最终都会被丢弃。因此,作为一项保障措施,我希望至少保留最年轻的Y = 7转储,即使是全部或部分转储超过21天。
我寻找比这意大利面条更优雅的东西:
DB_DUMP_DIR=/var/backups/dbs
RETENTION=$((21*24*60)) # 3 weeks
KEEP=7
find ${DB_DUMP_DIR} -type f -printf '%T@ %p\n' | \ # list all dumps with epoch
sort -n | \ # sort by epoch, oldest 1st
head --lines=-${KEEP} |\ # Remove youngest/bottom 7 dumps
while read date filename ; do # loop through the rest
find $filename -mmin +${RETENTION} -delete # delete if older than 21 days
done
(这个片段可能有小错误 - 忽略它们。这是为了说明我自己能想出什么,以及为什么我不喜欢它)
编辑:查找选项“-mtime”是一次性的:“ - mtime +21”表示实际上“至少22天”。那总是让我困惑,所以我用-mmin代替。仍然是一次性的,但只有一分钟。
答案 0 :(得分:3)
使用find
获取足以删除的所有文件,使用$KEEP
过滤掉tail
最年轻的文件,然后将其余文件传递给xargs
。
find ${DB_DUMP_DIR} -type f -printf '%T@ %p\n' -mmin +$RETENTION |
sort -nr | tail -n +$KEEP |
xargs -r echo
如果报告的文件列表是您要删除的列表,请将echo
替换为rm
。
(我假设没有一个转储文件的名字中有换行符。)
答案 1 :(得分:1)
您可以使用-mtime
代替-mmin
,这意味着您无需计算一天中的分钟数:
find $DB_DUMP_DIR -type f -mtime +21
您可以使用stat
命令按顺序对文件进行排序,而不是删除它们:
find $DB_DUMP_DIR -type f -mtime +21 | while read file
do
stat -f "%-10m %40N" $file
done | sort | awk 'NR > 7 {print $2}'
这将列出超过21天的所有文件,但不会列出超过21天的七个最年轻的文件。
从那里,您可以将其提供给xargs以执行删除:
find $DB_DUMP_DIR -type f -mtime +21 | while read file
do
stat -f "%-10m %40N" $file
done | sort | awk 'NR > 7 {print $2]' | xargs rm
当然,这都假设您的文件名中没有空格。如果你这样做,你将不得不采取稍微不同的方法。
这还将保留超过21天的七个最年轻的文件。您可能有比这更年轻的文件,并且不想真正保留这些文件。但是,您可以再次运行相同的序列(除了删除-mtime
参数:
find $DB_DUMP_DIR -type f | while read file
do
stat -f "%-10m %40N" $file
done | sort | awk 'NR > 7 {print $2} | xargs rm
您需要查看stat命令,了解该格式的选项。这因系统而异。我使用的是OS X.Linux与众不同。
我们采取略微不同的方法。我没有彻底测试过这个,但是:
如果所有文件都在同一目录中,并且没有文件名中包含空格:
ls -t | awk 'NR > 7 {print $0}'
将打印除<7个最年轻的文件之外的所有文件。也许我们可以坚持下去?
current_seconds=$(date +%S) # Seconds since the epoch
((days = 60 * 60 * 24 * 21)) # Number of seconds in 21 days
((oldest_allowed = $current_seconds - $days)) # Oldest allowed file
ls -t | awk 'NR > 7 {print $0}' | stat -f "%Dm %N" $file | while date file
do
[ $date < $oldest_allowed ] || rm $file
done
ls ... | awk
将削减七个最年轻的人。之后,我们可以使用stat来获取文件名和日期。由于日期是纪元之后的几秒钟,我们必须计算当前时间之前21天的时间是在纪元之前的几秒钟。
之后,它非常简单。我们查看文件的日期。如果它超过纪元之前的21天(即它的时间戳较低),我们可以将其删除。
正如我所说,我没有对此进行彻底测试,但是这将删除所有文件超过21天,只有21天以上的文件,但始终保持七个最年轻。
答案 2 :(得分:1)
我正在打开第二个答案因为我只有一个不同的解决方案 - 一个使用awk
:只需将时间添加到21天(以秒为单位),减去当前时间并删除否定时间! (在从列表中排序并删除最新的7之后):
DB_DUMP_DIR=/var/backups/dbs
RETENTION=21*24*60*60 # 3 weeks
CURR_TIME=`date +%s`
find ${DB_DUMP_DIR} -type f -printf '%T@ %p\n' | \
awk '{ print int($1) -'${CURR_TIME}' + '${RETENTION}' ":" $2}' | \
sort -n | head -n -7 | grep '^-' | cut -d ':' -f 2- | xargs rm -rf
答案 3 :(得分:1)
我最终使用的是:
for f in $(ls -1t | tail -n +31); do
if [[ $(find "$f" -mtime +30 -print) ]]; then
echo "REMOVING old backup: $f"
rm $f
fi
done
说明:
ls,按时间排序,跳过前 30 项:$(ls -1t | tail -n +31)
测试 find
是否可以找到超过 30 天的文件:if [[ $(find "$f" -mtime +30 -print) ]]
答案 4 :(得分:0)
你可以自己做循环:
t21=$(date -d "21 days ago" +%s)
cd "$DB_DUMP_DIR"
for f in *; do
if (( $(stat -c %Y "$f") <= $t21 )); then
echo rm "$f"
fi
done
我假设你有GNU date
答案 5 :(得分:0)
这些答案对我来说都不起作用,所以我改编了chepner的答案并且来到了这个,它只保留了最后$KEEP
个备份。
find ${DB_DUMP_DIR} -printf '%T@ %p\n' | # print entries with creation time
sort -n | # sort in date-ascending order
head -n -$KEEP | # remove the $KEEP most recent entries
awk '{ print $2 }' | # select the file paths
xargs -r rm # remove the file paths
我相信chepner的代码会保留$KEEP
最旧的,而不是最年轻的。
答案 6 :(得分:0)
从其他解决方案中提供的解决方案中,我进行了实验,发现了许多不需要的错误或情况。
这是我最后想出的解决方案:
# Sample variable values
BACKUP_PATH='/data/backup'
DUMP_PATTERN='dump_*.tar.gz'
NB_RETENTION_DAYS=10
NB_KEEP=2 # keep at least the 2 most recent files in all cases
find ${BACKUP_PATH} -name ${DUMP_PATTERN} \
-mtime +${NB_RETENTION_DAYS} > /tmp/obsolete_files
find ${BACKUP_PATH} -name ${DUMP_PATTERN} \
-printf '%T@ %p\n' | \
sort -n | \
tail -n ${NB_KEEP} | \
awk '{ print $2 }' > /tmp/files_to_keep
grep -F -f /tmp/files_to_keep -v /tmp/obsolete_files > /tmp/files_to_delete
cat /tmp/files_to_delete | xargs -r rm
这些想法是:
我的情况是,我每天有2个备份,并将NB_RETENTION_DAYS设置为10(因此,通常情况下,我通常有20个文件) 有人认为我可以这样设置NB_KEEP = 20,但实际上,我选择了NB_KEEP = 2,这就是为什么:
让我们想象一下我的备份脚本已损坏,而我一个月都没有备份。我真的不在乎拥有30天以上的20个最新文件。我想要至少拥有一个。 但是,能够轻松识别出问题非常重要(显然我的监视系统确实是盲目的,但这是另一点)。而且,我的备份文件夹中的文件比平时少10倍,这也许会引起注意……
答案 7 :(得分:-1)
这里是一个BASH函数,应该可以解决问题。我无法轻易避免两次find
的调用,但是除此之外,这是相对成功的:
# A "safe" function for removing backups older than REMOVE_AGE + 1 day(s), always keeping at least the ALWAYS_KEEP youngest
remove_old_backups() {
local file_prefix="${backup_file_prefix:-$1}"
local temp=$(( REMOVE_AGE+1 )) # for inverting the mtime argument: it's quirky ;)
# We consider backups made on the same day to be one (commonly these are temporary backups in manual intervention scenarios)
local keeping_n=`/usr/bin/find . -maxdepth 1 \( -name "$file_prefix*.tgz" -or -name "$file_prefix*.gz" \) -type f -mtime -"$temp" -printf '%Td-%Tm-%TY\n' | sort -d | uniq | wc -l`
local extra_keep=$(( $ALWAYS_KEEP-$keeping_n ))
/usr/bin/find . -maxdepth 1 \( -name "$file_prefix*.tgz" -or -name "$file_prefix*.gz" \) -type f -mtime +$REMOVE_AGE -printf '%T@ %p\n' | sort -n | head -n -$extra_keep | cut -d ' ' -f2 | xargs -r rm
}
它需要一个backup_file_prefix
环境变量,或者可以将其作为第一个参数传递,并且期望环境变量ALWAYS_KEEP
(要保留的最小文件数)和REMOVE_AGE
(要经过的天数)到-mtime
)。它需要一个gz
或tgz
扩展名。您可以在注释中看到其他一些假设,其中大部分是以安全为名的。
感谢ireardon和his answer(不能完全回答问题)来获得灵感!
快乐的安全备份管理:)