我们遇到一个问题,就是文件夹变得难以处理成千上万个小文件。

文件太多,执行rm -rf会返回错误,而我们需要做的事情是这样的:

find /path/to/folder -name "filenamestart*" -type f -exec rm -f {} \;

此方法有效,但速度很慢,并且经常会因内存不足而失败。

是否有更好的方法?理想情况下,我希望删除整个目录而不关心其中的内容。

评论

文件夹中的rm -rf *可能由于参数过多而失败;但是如果您仍然要删除整个目录,那么rm -rf folder /呢?

建议不要将该文件夹放在一个单独的分区上,而只需手动卸载&&格式化&&重新安装。

出于好奇-破解rm -rf需要多少文件?

您可能应该将问题重命名为更准确的名称,例如“有效删除包含数千个文件的大型目录”。为了删除目录及其内容,根据定义,必须进行递归。您可以手动将目录inode本身本身手动断开链接(可能需要root特权),卸载文件系统,然后在其上运行fsck来回收未使用的磁盘块,但是这种方法似乎有风险,而且可能不会更快。此外,文件系统检查可能仍涉及以递归方式遍历文件系统树。

一旦我的ccache文件树变得如此巨大,并且rm花费了如此长的时间(并使整个系统呆滞),从文件系统中复制所有其他文件,格式化并复制回它们的速度就快得多。从那时起,我给如此庞大的小文件树提供了自己的专用文件系统,因此您可以直接使用mkfs代替rm。

#1 楼

使用rsync令人惊讶,快速且简单。

mkdir empty_dir
rsync -a --delete empty_dir/    yourdirectory/


@sarath的答案提到了另一个快速选择:Perl!它的基准测试速度比rsync -a --delete快。 unix-fast-remove-directory-for-cleaning-up-daily-builds
http://www.slashroot.in/which-is-the-fastest-method-to-delete-files-in-linux


评论


谢谢,非常有用。我一直在使用rsync,我不知道您可以使用rsync这样删除。比rm -rf快得多

–约翰·鲍威尔(John Powell)
2014年8月21日在19:41

rsync可以比普通rm更快,因为它保证删除顺序正确,因此需要较少的btress重新计算。看到这个答案serverfault.com/a/328305/105902

– Marki555
15年6月29日在12:45

任何人都可以修改perl表达式以递归删除directory_to_be_deleted中的所有目录和文件吗?

– Abhinav
2015年10月6日15:43

注意:在rsync上添加-P选项可获得更多显示,此外,请注意语法,斜杠是必需的。最后,您可以首次使用-n选项来首次启动rsync命令以启动试运行。

–Drasill
15-10-23在15:39

****极端警告****是Gobinath(在上面的评论中)在上面的github.com地址生成的脚本。根据我的实验,这可能会导致数据意外丢失……尤其是我认为,这似乎会导致符号链接被浏览并且其内容被删除。我建议大家在认真使用它之前先进行详细的试验!

–麦克·啮齿动物
20年1月10日在19:03

#2 楼

Twitter上有人建议使用-delete而不是-exec rm -f{} \;

这样可以提高命令的效率,尽管如此,它仍然使用递归来遍历所有内容。

评论


这是非标准的。 GNU查找具有-delete,也许其他查找。

– Enzotib
2012年4月26日上午9:11

出于安全和效率考虑,在可用时,始终应优先于-exec rm使用-delete。

– jw013
2012年4月26日上午11:37

GNU是事实上的标准。

–罗恩·约翰(RonJohn)
18年3月3日在17:38

只是警告-在gnu find中添加-delete会隐式启用-depth,这使您回到扫描期间内存不足的问题。

–戴夫
20年12月11日,0:05

#3 楼

诸如此类的事情:
find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

您可以通过更改参数-n的参数来限制一次删除的文件数。还包括带有空白的文件名。

评论


您可能不需要-n 20位,因为xargs应该将其自身限制为可接受的参数列表大小。

–没用
2012年4月26日13:41

是的,你是对的。这是man xargs的注释:(...)每个命令行(...)的最大字符数。允许的最大值取决于系统,并且被计算为exec的参数长度限制。因此,-n选项适用于xargs无法确定CLI缓冲区大小或执行的命令具有某些限制的情况。

–digital_infinity
2012年4月26日13:50



#4 楼

一个巧妙的技巧:

rsync -a --delete empty/ your_folder/


它占用大量的CPU资源,但速度确实非常快。参见https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/zh/linux/a-fast-way-to-remove-huge-number-of-files.html

评论


速度不是很快,因为它无法有效地读取目录内容。请参阅此答案以获取10倍更快的解决方案和说明serverfault.com/a/328305/105902

– Marki555
15年6月29日在12:46

@ Marki555:在问题的编辑中,rsync -a --delete报告为60秒,而lsdent报告为43秒。比率10x对于时间ls -1 | wc -l vs time ./dentls bigfolder> out.txt(由于> file vs wc -l,这是部分公平的比较)。


16年1月21日在9:30

那里的问题是,那里的命令中没有一个实际上执行删除所需的遍历操作。他们给的密码?不能按Marki555所述工作。

–斯瓦尔塔夫
18-09-10的16:05

#5 楼

扩展其中一条评论,我认为您没有按照自己的想法做。

首先,我创建了大量的文件来模拟您的情况:

$ mkdir foo
$ cd foo/
$ for X in $(seq 1 1000);do touch {1..1000}_$X; done


然后我尝试了我预期会失败的事情,听起来像是您在做这个问题: >但这确实有效:

$ rm -r foo/*
bash: /bin/rm: Argument list too long


评论


这是唯一有效的解决方案:多次运行rm -Rf bigdirectory。我有一个包含成千上万个子目录和文件的目录。我什至无法在该目录中运行ls或find或rsync,因为它内存不足。 rm -Rf命令多次退出(内存不足),仅删除了数十亿文件的一部分。但是经过多次重试,它终于完成了工作。如果出现内存不足的问题,这似乎是唯一的解决方案。

–erik
2014年4月9日在13:01



#6 楼

-delete相比,我有机会测试-exec rm \{\} \;,对我来说-delete是此问题的答案。 br />
“如何在linux中删除大量文件”一文表明它的速度快了大约三倍,但在我的测试中,区别要大得多。

评论


使用find -exec对每个文件分别执行rm命令,这就是为什么它这么慢的原因。

– Marki555
15年6月26日在21:43

使用GNU find,这是-exec rm {} \ +派上用场的地方(特别是\ +代替\;),因为它像内置xargs一样工作,而没有最少的管道和派生开销。不过,它仍然比其他选项慢。

– dannysauer
19/12/2在23:12

@dannysauer execplus由AT&T的David Korn于1988年发明,GNU find是最后一个添加支持的实现-超过25年。顺便说一句:标准execplus和非标准-delete之间的速度差异很小。

–schily
20-2-22在10:09

@schily,这很有趣,我非常喜欢Korn的作品。但是,我们正在评论的答案表明测试是在Linux上进行的。指定了“ GNU查找”以区别于其他可能的最小Linux实现,例如busybox。 :)

– dannysauer
20-2-23在4:12

#7 楼

请使用rm -rf directory而不是rm -rf *。但是随后,我们的一位高级工程师建议我们避免使用星号(rm -rf *),而应将其传递给父目录,例如*

经过一番激烈的辩论之后,我们决定对它进行基准测试,以及使用rm -rf directory的第三种方法。结果如下:

time rm -rf *                   2m17.32s
time rm -rf directory           0m15.60s
time find directory -delete     0m16.97s


findrm -rf directory快9倍!

不用说,我们买了工程师啤酒!

所以现在我们使用rm -rf *删除目录并重新创建。

评论


问题是*进行了shell扩展,这意味着:(a)读取整个目录,然后(b)甚至在调用find之前对所有文件名进行排序。使用ls -1 -U以串行顺序读取目录。您可以输入-n 10000并获取要发送到xargs rm的列表。并且由于这些名称在目录的第一部分都是串行的,因此它们也被有效地删除。只需将其循环,直到没有剩余文件,它就会很好地工作。

– Paul_Pedant
19年11月15日在21:05



感谢@Paul_Pedant的推理!

–约书亚·品特(Joshua Pinter)
19年11月15日在21:21

#8 楼

关于上面的-delete选项:我正在使用它删除我创建的temp文件夹中的大量(1M + est)文件,并且无意中忘记了每晚进行清理。我不小心填充了磁盘/分区,除find .命令外,其他都无法删除它们。它很慢,起初我使用的是:

find . -ls -exec rm {} \;


但这要花费大量时间。它大约在15分钟后开始删除某些文件,但是我猜测它在最终启动后每秒删除的速度不到10左右。因此,我尝试了:

find . -delete


,我现在就让它运行。它看起来运行得更快,尽管它在CPU上的工作量极高,而其他命令却没有。它已经运行了大约一个小时,我想我的驱动器上的空间已经恢复了,分区逐渐“缩小”,但是仍然需要很长时间。我严重怀疑它的运行速度比其他设备快1000倍。在所有情况下,我只想指出空间与时间之间的权衡。如果您有空闲的CPU带宽(我们愿意),请运行后者。我的CPU正在运行(uptime报告):通常负载很轻,几个小时就可以了。我已经检查了系统上的大多数其他内容,但它们仍然可以响应,因此我们现在可以了。

评论


如果要使用exec,则几乎可以肯定不使用-ls并执行find。 -type f -exec rm'{}'+ +更快,因为它将为rm提供尽可能多的参数。

– xenoterracide
2014年1月3日,17:48

我认为您应该继续进行编辑并将其编辑为自己的答案...评论实在太久了。而且,听起来您的文件系统具有相当昂贵的删除功能,您好奇它是哪一个?您可以通过nice或ionice运行该find ...- delete,这可能会有所帮助。因此,可能会将某些安装选项更改为不太安全的设置。 (当然,取决于文件系统上的其他内容,删除所有内容的最快方法通常是mkfs。)

–德罗伯特
2014年1月4日7:24



平均负载并不总是CPU,它只是随时间推移阻塞进程数的度量。进程可能会阻塞磁盘I / O,这很可能在这里发生。

–Score_Under
14年7月14日在12:47

另请注意,平均负载并未考虑逻辑CPU的数量。因此,单核计算机的loadavg 1与64核系统上的loadavg 64相同-意味着每个CPU 100%的时间都处于繁忙状态。

– Marki555
15年6月29日在12:49

#9 楼

考虑使用Btrfs卷,只需为包含大量文件的目录删除整个卷即可。 br />

#10 楼

有几种方法可用于删除linux中的大量文件。您可以将find与delete选项一起使用,这比exec选项要快。然后您可以使用perl取消链接,甚至可以使用rsync。
如何在linux中删除大量文件

#11 楼

假设已安装GNU parallel,我已经使用了它:

parallel rm -rf dir/{} ::: `ls -f dir/`

它足够快。

#12 楼

正如我从本站点中学到的那样,删除REALLY LARGE目录需要一种不同的方法-您需要利用ionice,它可以确保-c3删除仅在系统具有IO时间的情况下执行。您的系统负载不会增加到很高,并且所有内容都保持响应(尽管我的CPU查找时间相当长,大约为50%)。

find <dir> -type f -exec ionice -c3 rm {} \;


评论


用+代替\;一次将更多的参数传递给rm时,将使此过程更快,减少分叉

– xenoterracide
2014年1月3日17:50

为什么不ionice -c3找到 -type f -delete

– jtgd
18-10-27在12:57



#13 楼

如果您有数百万个文件,并且上述每个解决方案都使您的系统处于压力之下,则可以尝试以下启发:

nice_delete文件:现在删除文件:

#!/bin/bash

MAX_LOAD=3
FILES=("$@")
BATCH=100

while [ ${#FILES[@]} -gt 0 ]; do
    DEL=("${FILES[@]:0:$BATCH}")
    ionice -c3 rm "${DEL[@]}"
    echo -n "#"
    FILES=("${FILES[@]:$BATCH}")
    while [[ $(cat /proc/loadavg | awk '{print int()}') -gt $MAX_LOAD ]]; do
        echo -n "."
        sleep 1
    done
done


查找将创建约数万个文件的批处理(请参阅getconf ARG_MAX)并将其传递给nice_delete。这将创建更小的批次,以在检测到过载时允许睡眠。

#14 楼

ls -1 | xargs rm -rf 


应在主文件夹中工作

评论


由于文件夹中的文件数量过多,ls无法正常工作。这就是为什么我不得不使用find的原因,谢谢。

–托比
2012年4月26日在8:19

@Toby:尝试使用ls -f禁用排序。排序要求将整个目录加载到要排序的内存中。未排序的ls应该能够流式传输其输出。

– camh
2012年4月26日上午10:59

不适用于包含换行符的文件名。

–maxschlepzig
2014年1月5日7:53

@camh是真的。但是,按排序顺序删除文件要比按未排序顺序删除文件更快(因为每次删除后都要重新计算目录的btree)。请参阅此答案以获取示例serverfault.com/a/328305/105902

– Marki555
2015年6月29日12:50



@maxschlepzig用于此类文件,您可以使用find。 -print0 | xargs -0 rm,它将使用NULL char作为文件名分隔符。

– Marki555
15年6月29日在12:51

#15 楼

对于上述Izkata的提示:


但这确实有效:工作-但是我在许可方面遇到了一些问题;文件在服务器上,但是我仍然不知道此权限问题来自何处。无论如何,终端要求对每个文件进行确认。文件数量约为20000,因此这不是一个选择。在“ -r”之后,我添加了选项“ -f”,因此整个命令为“ rm -r -f foldername /”。然后它似乎工作正常。我是Terminal的新手,但我想这还好吧?谢谢!

#16 楼

根据您需要如何清除这些文件,我建议使用shred。如果要清除目录,则不能使用q4312079q。
删除它并重新创建它,我建议将其移动并立即重新创建。切记:您无法真正在多核计算机上并行化此测试。它取决于磁盘访问,而磁盘访问受RAID或您所拥有的限制。

评论


shred无法与许多现代文件系统一起使用。

–user26112
2013年7月2日14:47



#17 楼

如果您只想尽快清除许多文件,则ls -f1 /path/to/folder/with/many/files/ | xargs rm可能会正常工作,但最好不要在生产系统上运行它,因为您的系统可能会成为IO问题,并且在删除操作期间应用程序可能会卡住。

此脚本可很好地用于许多文件,并且不应影响系统的ioload。

#!/bin/bash

# Path to folder with many files
FOLDER="/path/to/folder/with/many/files"

# Temporary file to store file names
FILE_FILENAMES="/tmp/filenames"

if [ -z "$FOLDER" ]; then
    echo "Prevented you from deleting everything! Correct your FOLDER variable!"
    exit 1
fi

while true; do
    FILES=$(ls -f1 $FOLDER | wc -l)
    if [ "$FILES" -gt 10000 ]; then
        printf "[%s] %s files found. going on with removing\n" "$(date)" "$FILES"
        # Create new list of files
        ls -f1 $FOLDER | head -n 5002 | tail -n 5000 > "$FILE_FILENAMES"

        if [ -s $FILE_FILENAMES ]; then
            while read FILE; do
                rm "$FOLDER/$FILE"
                sleep 0.005
            done < "$FILE_FILENAMES"
        fi
    else
        printf "[%s] script has finished, almost all files have been deleted" "$(date)"
        break
    fi
    sleep 5
done


#18 楼

使用ls -f | xargs -n 5000 rm,同时调整-n的批次大小以适合您的系统(对于-n提示,请使用@digital_infinity表示感谢)。另外,您还可以使用内联grep过滤列表,例如ls -f | grep '^156' | xargs -n 5000 rm

根据我的经验,这比使用find的技术快得多,并且消除了对更复杂的shell脚本的需求。

#19 楼

Python脚本不应该被认为是不干净的:从我的实验来看,它似乎还不错。

可以处理NB错误以至少将它们打印出来...但是之后运行trash myDirectoryForDeletionrm -rfv myDirectoryForDeletion可能会更简单。