我有一个脚本,当超过设定限制时,我想清除旧文件。
我有这个命令:
/bin/rm -f `/bin/ls -t $bkup_p/mysql.daily/* 2> /dev/null | /bin/awk 'NR>'5`
这是可行的,因为 $bkup_p 中可能有空格,我尝试将其更改为
/bin/rm -f `/bin/ls -t "$bkup_p/mysql.daily/*" 2> /dev/null | /bin/awk 'NR>'5`
但这是行不通的。它不显示有问题的文件,它只是空的
答案1
在根据修改时间过滤文件并对其执行命令时,Bash 并不是很方便。
我建议尝试 z-shell,所以首先运行zsh
,然后
rm -i -- "$bkup_p"/mysql.daily/*(DN.Om[1,5])
这将删除给定目录中最旧的五个纯文件,我怀疑可能就是您想要实现的目标。显然,如果需要的话,最终会更改rm -i
为rm -f
。
要删除五个最新文件,请执行以下操作
rm -i -- "$bkup_p"/mysql.daily/*(DN.om[1,5])
现在,它是如何工作的。里面的所有内容()
都是所谓的 glob 限定符,它基本上根据您的需要过滤文件:
D
包括点文件(以 开头的文件.
)N
如果没有匹配则不报告错误.
仅选择纯文件om
按修改时间排序(Om
逆序排序)[1,5]
从列表中仅选择五个文件
我相信所有这些都应该适用于文件名中的特殊字符(空格、换行符等)
答案2
正如其他人所说,您不应该用于ls
此目的。但是如果你的环境没有任何更明智的东西并且你了解注意事项, 你可能如果你的文件名是足够好:没有空格或者不可打印的字符,尤其是没有被 shell 解释为通配符的字符(至少?*[]
)。
使用 Perl 之类的东西对文件进行排序,或者将日期放在文件名中以便您可以依赖全局顺序会更好。
话虽如此:在您的第二个片段中,星号被引用,因此不会发生通配符。您会看到有关不存在的错误some dir/mysql.daily/*
,但由于您将错误输出重定向走了,所以您没有看到。
带有空格的文件名会给您带来一个问题,即命令替换的输出沿空格分割,因此类似的内容some dir/foo
将分为rm
两部分:some
和dir/foo
。希望它们都不存在,因为它们会被删除。
如果只有您的目录名称包含空格,您可以先cd
进入它。或者,设置IFS
为仅包含换行符(而不是默认的空格、制表符、换行符)。您提到了 NAS,那么您很可能拥有 busybox。这应该适用于 busybox 和 bash,并打印文件名,每行一个:
IFS=$'\n'
printf "%s\n" $( ls -t "$bkup_p/mysql.daily/"* | tail -n +6 )
如果您确定其工作正常,请替换printf "%s\n"
为rm
以删除文件。
答案3
我建议不要解析 的输出,ls
因为它不能正确格式化输出以通过管道传输到新命令,并且它存在可移植性问题。
我会尝试这样的事情
find $bkup_p/mysql.daily/ -type f -a -mtime +7 -a -name "*.sql" -a -exec rm -f {} +
笔记:
"*.sql"
根据需要更改此设置-mtime +7
意味着*如果此文件在 7 天前被修改了更多 (+),显然也可以根据需要更改此文件
如果您想确保始终拥有 10 个最新文件 - 无论如何,(并且您有 GNU find
)您可以尝试
find $bkup_p/mysql.daily/ -maxdepth 1 -type f -a -printf "%T+\t%p\n" | sort -r | sed -n '10,$p' | awk '{print $2}' | xargs rm -f
有关使用运算find
符格式化输出的更多信息-printf
,请参阅
man find | less '+/^\s*-printf'
答案4
不起作用的问题*
是因为当您引用它时,它不会扩展。
将以下结果echo *
与以下结果进行比较:echo "*"
。
可靠的解决方案是使用一个数组,每个数组位置上有一个文件。
如果你足够幸运并且你的发现支持这一点-printf
:
dir="$bkup_p/mysql.daily/"
find "$dir" -printf '%T@:%i\n'
所有文件名都将被避免。每个文件都是一行。一行仅包含数字、可选的点和冒号。
这可以很容易地排序:
find "$dir" -printf '%T@:%i\n' | sort -rn
最简单的数组是位置参数。
这会将目录中的所有文件设置为位置参数列表:
set -f; set -- $(find "$dir" -printf '%T@:%i\n' | sort -n )
set -f 将避免扩展任何也是通配符的文件名*
。要避免(删除)前 6 个文件名,只需shift
:
shift 5
对其余文件执行您需要的操作:
for f
do rm -f "$(find "$dir" -inum "${f#*:}")"
done
整个剧本。
整个脚本(对于任何文件名都稳健)变为:
dir="$bkup_p/mysql.daily/"
set -f
set -- $(find "$dir" -type f -printf '%T@:%i\n'|sort -rn)
shift 5
for f
do rm -f "$(find "$dir" -inum "${f#*:}")"
done