我刚接触shell脚本编程,需要帮助。 我有一个备份文件目录。如果有超过10个备份文件,我想要删除最旧的文件,以便只留下最新的10个备份文件。
到目前为止,我知道如何计算文件数量,这似乎很容易,但如果文件数超过10,如何删除最旧的文件呢?
if [ls /backups | wc -l > 10]
then
echo "More than 10"
fi
试试这个:
ls -t | sed -e '1,10d' | xargs -d '\n' rm
这应该能处理文件名中的所有字符(除了换行符)。
这里发生了什么?
ls -t
按修改时间递减顺序列出当前目录中的所有文件。也就是说,最近修改的文件排在前面,每行一个文件名。sed -e '1,10d'
删除前10行,即最新的10个文件。我使用它而不是 tail
,因为我总是记不住是需要 tail -n +10
还是 tail -n +11
。xargs -d '\n' rm
收集每个输入行(不包括结束换行符),并将每行作为参数传递给 rm
。像这样的任何操作,请在安全的地方进行实验。
sed -e 1,10d
正是它所说的:删除前10行。 - Dale Hagglundls
命令的输出中删除它们,管道的以下部分会删除所有旧文件。 - Dale Hagglund-r
选项,当使用时,仅在存在非空行时才运行xargs。 因此,将该选项添加到xargs
中可以消除错误。 - Chrisfind
是这种任务中常用的工具:
find ./my_dir -mtime +10 -type f -delete
解释
./my_dir
你的目录(用你自己的替换)-mtime +10
大于10天之前的文件-type f
只有文件-delete
毫不意外。在执行整个命令之前,删除它来测试你的find
过滤器请确保./my_dir
存在以避免出现意外情况!
find
将遍历整个目录树,在任何级别删除文件。在这里,OP也没有要求此行为。 - Dale Hagglund请确保您的pwd是正确的目录以删除文件,然后(假设文件名中仅有常规字符):
ls -A1t | tail -n +11 | xargs rm
保留最新的10个文件。我结合相机程序“motion”使用它来保留最近的抓拍文件。感谢之前所有的答案,因为你们向我展示了如何实现。
这种情况的正确处理方式是使用logrotate
。
logrotate
是一个不错的选择,但它可能有点过于复杂:需要配置文件,并且在某种程度上偏向于半官方的日志文件位置。此外,它是否假定应该先旋转日志(即将 .N 重命名为 .N+1),然后再删除最旧的日志?至少按照写作方式,OP 的问题并没有暗示固定名称的旋转。 - Dale Hagglund我喜欢@Dennis Williamson和@Dale Hagglund的回答。(对每个人+1)
这里是另一种使用find
(带有-newer
测试)的方法,与您开始的方式类似。
这是在cygwin上的bash中完成的...
if [[ $(ls /backups | wc -l) > 10 ]]
then
find /backups ! -newer $(ls -t | sed '11!d') -exec rm {} \;
fi
简单的文件计数器:
max=12
n=0
ls -1t *.dat |
while read file; do
n=$((n+1))
if [[ $n -gt $max ]]; then
rm -f "$file"
fi
done
rm
"需要整个路径。我的使用的CUxD Exec命令不能在所选文件夹中启动。因此,这是我的解决方案:
ls -A1t $(find /media/usb0/backup/ -type f -name homematic-raspi*.sbk) | tail -n +11 | xargs rm
解释:
find /media/usb0/backup/ -type f -name homematic-raspi*.sbk
在文件夹 /media/usb0/backup/
中搜索名字类似于 homematic-raspi*.sbk
(区分大小写)的文件,使用 -iname
(不区分大小写)也可以。ls -A1t $(...)
列出由 find
返回的文件,不包括以 "." 或 ".." 开头的文件 -A
,按修改时间排序 -t
,只返回一列 -1
。tail -n +11
只返回最后10行之后的内容,用于接下来的 rm
。xargs rm
最后删除列表中剩余的文件。希望这能帮助其他人更快地找到答案并使解决方案更加灵活。
MIN_FILES=5
FILE_COUNT=$(ls -l | grep -c ^d )
if [ $MIN_FILES -lt $FILE_COUNT ]; then
while [ $MIN_FILES -lt $FILE_COUNT ]; do
FILE_COUNT=$[$FILE_COUNT-1]
FILE_TO_DEL=$(ls -t | tail -n1)
# be careful with this one
rm -rf "$FILE_TO_DEL"
done
fi
解释:
FILE_COUNT=$(ls -l | grep -c ^d )
统计当前文件夹中的所有文件数量。我们也可以使用wc -l
,但该主机上未安装wc。FILE_COUNT=$[$FILE_COUNT-1]
更新当前的$FILE_COUNT
。FILE_TO_DEL=$(ls -t | tail -n1)
将最旧的文件名保存在$FILE_TO_DEL
变量中。tail -n1
返回列表中的最后一个元素。stat -c "%Y %n" * | sort -rn | head -n +10 | \
cut -d ' ' -f 1 --complement | xargs -d '\n' rm
步骤:获取每个文件的最后修改时间(格式为“时间
文件名
”),按从旧到新的顺序排序,保留除最后十个条目外的所有条目,然后保留除第一个字段外的所有内容(仅保留文件名部分)。
编辑:使用cut
代替awk
,因为后者并不总是可用。
编辑2:现在处理带有空格的文件名。
根据他人的建议和一些awk技巧,我让它工作了。我知道这是一个旧的线程,但我在这里没有找到一个像样的答案,而这个方法对我很有用。这只是删除最旧的文件,但你可以将head -n 1更改为10,以获取最旧的10个文件。
find $DIR -type f -printf '%T+ %p\n' | sort | head -n 1 | awk '{first =$1; $1 =""; print $0}' | xargs -d '\n' rm
if [ $(ls /backups | wc -l) -gt 10 ]
。基本上,方括号内的空格很重要,管道命令需要用$()
包装,而在方括号内比较数字时使用-gt
而不是>
。 - Chris