我正在尝试使用Debian中的脚本删除树中最旧的文件。
find /home/backups -type f \( -name \*.tgz -o -name \*.gz \) -print0 | xargs -0 ls -t | tail -1 | xargs -0 rm
但是我收到了一个错误:
rm: cannot remove `/home/backups/tree/structure/file.2011-12-08_03-01-01.sql.gz\n': No such file or directory
任何想法我做错了(或者有更简单/更好的方法吗?),我尝试过RTFM,但我迷路了。
答案 0 :(得分:11)
ls
附加换行符,最后一个xargs -0表示换行符是文件名的一部分。
使用-d '\n'
而不是-0
运行最后一个xargs。
find
生成的一个非常长的文件名列表,以便xargs -0 ls
使用文件名的子集多次运行ls
。只有最早的最后ls
次调用会使其超过tail -1
。如果最早的文件实际上是,例如find
输出的第一个文件名,则删除较年轻的文件。
答案 1 :(得分:3)
任何涉及ls
的解决方案都是绝对错误的。
执行此操作的正确方法是使用find
获取文件集sort
按时间顺序排序,过滤掉除第一个之外的所有文件,然后删除rm
。 @Ken这个大概是正确的,只缺少一些细节。
find /home/backups -type f \( -name \*.tgz -o -name \*.gz \) -printf '%T@ %p\0' |\
sort -z -n | \
{ IFS= read -d '' file ; [ -n "$file" ] && echo rm -f "$(cut -d' ' -f2- <<<"$file")" ; }
删除上面的echo
以实际执行删除。
上述代码甚至适用于文件名中包含空格,换行符或其他异常值的文件。当没有结果时,它也不会造成任何伤害。
如果你不关心打破文件名中的换行符,这会更容易
find /home/backups -type f \( -name \*.tgz -o -name \*.gz \) -printf '%T@ %p\n' |\
sort -n |\
head -n 1 |\
cut -d' ' -f2- |\
xargs echo rm
不同之处在于我们可以依赖head
并且可以在管道上使用cut
而不是做任何疯狂的事情。
答案 2 :(得分:2)
您还可以使用find随意打印修改时间,排序,剪切和xargs:
find /home/backups -printf "%T@ %p\n" | sort -n | head -1 | cut -d" " -f2- | xargs ls -al
答案 3 :(得分:1)
ls
以分隔符的形式发出换行符,因此您需要将第二个xargs -0
替换为xargs -d '\n'
。但是,如果最旧的文件名称中有换行符,则会中断。
答案 4 :(得分:0)
修改我错过了那里的ls -t
。
我可能会建议这样做更简单,例如。
find /home/backups \
-type f -iregex '.*\.t?gz$' \
-mtime +60 -exec rm {} \;
将删除任何早于特定年龄的匹配文件(示例中为60天)
您使用了 tail
,但没有告诉它寻找空分隔符。
无论如何,这是一个可用于返回最后一个0分隔元素的util:
#include <string>
#include <iostream>
#include <cstdio>
int main(int argc, const char *argv[])
{
std::cin.unsetf(std::ios::skipws);
if (! (freopen(NULL, "wb", stdout) && freopen(NULL, "rb", stdin) ))
{
perror("Cannot open stdout/in in binary mode");
return 255;
}
std::string previous, element;
while (std::getline(std::cin, element, '\0'))
{
previous = element;
// if you have c++0x support, use this _instead_ for performance:
previous = std::move(element);
}
std::cout << previous << '\0' << std::flush;
}
将其用作
find /home/backups -type f \( -name \*.tgz -o -name \*.gz \) -print0 | ./mytail | xargs -0 rm
答案 5 :(得分:0)
ls -tr $(find /home/backups -name '*.gz' -o -name '*.tgz')|head -1|xargs rm -f
答案 6 :(得分:0)
find /home/backups -type f \( -name \*.tgz -o -name \*.gz \) -print0 | xargs -0 stat --format '%010Y:%n' | sort -n | head -n 1 | cut -d: -f2- | xargs -d '\n' rm
来自:Sort a file list by Date in Linux (Including Subdirectories)