我想在 cronjob 中放置一个脚本,该脚本将在特定时间运行,如果文件计数超过 60,它将从该文件夹中删除最旧的文件。后进先出。我努力了,
#!/bin/ksh
for dir in /home/DABA_BACKUP
do
cd $dir
count_files=`ls -lrt | wc -l`
if [ $count_files -gt 60 ];
then
todelete=$(($count_files-60))
for part in `ls -1rt`
do
if [ $todelete -gt 0 ]
then
rm -rf $part
todelete=$(($todelete-1))
fi
done
fi
done
这些都是每天保存并命名为 的备份文件backup_$date
。这个可以吗?
答案1
不,一方面它会破坏包含换行符的文件名。它也比必要的更复杂,并且具有以下所有危险解析 ls。
更好的版本是(使用 GNU 工具):
#!/bin/ksh
for dir in /home/DABA_BACKUP/*
do
## Get the file names and sort them by their
## modification time
files=( "$dir"/* );
## Are there more than 60?
extras=$(( ${#files[@]} - 60 ))
if [ "$extras" -gt 0 ]
then
## If there are more than 60, remove the first
## files until only 60 are left. We use ls to sort
## by modification date and get the inodes only and
## pass the inodes to GNU find which deletes them
find dir1/ -maxdepth 1 \( -inum 0 $(\ls -1iqtr dir1/ | grep -o '^ *[0-9]*' |
head -n "$extras" | sed 's/^/-o -inum /;' ) \) -delete
fi
done
请注意,这假设所有文件都位于同一文件系统上,如果不是,则可能会产生意外结果(例如删除错误的文件)。如果有多个硬链接指向同一个 inode,它也无法正常工作。
答案2
#! /bin/zsh -
for dir (/home/DABA_BACKUP/*) rm -f $dir/*(Nom[61,-1])
为了zsh-无知;-):
for var (list) cmd
:循环的简短版本for var in list; do cmd; done
(让人想起perl
语法)。$dir
:zsh
变量不需要像在其他 shell 中那样加zsh
引号明确的split
和glob
运算符所以不做隐式分割+全局参数扩展时。*(...)
: 与全局限定符:N
:nullglob
: 当不匹配时,glob 会扩展为空,而不是引发错误。m
:哦将生成的文件放在米修改时间(最小的在前)。[61,-1]
:从该有序列表中选择倒数第 61 个。
所以基本上删除了除 60 个最年轻的文件之外的所有文件。
答案3
要获取要删除的最旧条目的列表(从而保留 60 个最新条目):
ls -t | tail -n +61
请注意,您的方法的主要问题仍然需要在这里解决:如何处理带有换行符的文件,以防万一;否则你可以使用(替换你相当复杂的程序):
cd /home/DABA_BACKUP || exit 1
ls -t | tail -n +61 | xargs rm -rf
注意:因为看起来你有每日备份您也许还可以使用基于文件日期和的方法find
;如:
find /home/DABA_BACKUP -mtime +60 -exec ls {} +
(ls
在仔细检查正确操作后,该命令将被适当的命令替换rm
)。
答案4
如果您知道文件都名为 backup_*,则应该将其包含在 ls 命令中,这样您只处理这些文件,而不处理意外进入目录的文件。然后ls用在管道中,每行只列出1个文件,然后只计数,不需要排序,所以
count_files=$(ls -U backup_* | wc -l)
和
for part in $(ls -rt backup_*);do
rm -rf "$part"
todelete=$(($todelete-1))
if [[ $todelete -eq 0 ]]; then
break
fi
done