有效删除包含数千个文件的大目录


159

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

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

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

这可以正常工作,但是速度很慢,并且经常由于内存不足而失败。

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


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

4
我建议不要将该文件夹放在单独的分区上,而只需手动卸载&&格式化&&重新安装,而不是手动删除它。
bbaja42 '04

7
出于好奇-破解多少个文件rm -rf
2012年

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

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

Answers:


211

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

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

@sarath的答案提到了另一个快速选择:Perl!其基准测试速度比快rsync -a --delete

cd yourdirectory
perl -e 'for(<*>){((stat)[9]<(unlink))}'

资料来源:

  1. https://stackoverflow.com/questions/1795370/unix-fast-remove-directory-for-cleaning-up-daily-builds
  2. http://www.slashroot.in/which-is-the-fastest-method-to-delete-files-in-linux

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

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

7
任何人都可以修改Perl表达式递归删除里面所有的目录和文件directory_to_be_deleted
Abhinav 2015年

5
注意:-P在rsync上添加选项以显示更多内容,并且请注意语法,斜杠必需的。最后,您可以首次启动rsync命令,并首先-n选择启动空运行
Drasill 2015年

1
-a等于-rlptgoD,但仅对于删除-rd是必要的
Koen。

38

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

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


11
这是非标准的。GNU find-deletefind也许其他。
enzotib 2012年

13
-delete-exec rm出于安全和效率的考虑,应始终优先选择可用的设备。
2012年

6
GNU是事实上的标准。
罗恩·约翰(RonJohn)

17

怎么样呢? find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

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


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

是的,你是对的。这是来自的笔记man xargs(...) max-chars characters per command line (...). The largest allowed value is system-dependent, and is calculated as the argument length limit for exec。因此,此-n选项适用于xargs无法确定CLI缓冲区大小或执行的命令具有某些限制的情况。
digital_infinity 2012年

12

一个聪明的把戏:

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 2015年

2
@ Marki555:在问题的编辑中,报告为60秒,而报告为rsync -a --delete43 秒lsdent。比10倍是为 time ls -1 | wc -l VS time ./dentls bigfolder >out.txt(即由于部分公平的比较 > fileVS wc -l)。
Hastur

问题存在这样NONE那边的命令的实际DO所需遍历操作为删除。他们给出的代码?不能按Marki555所述工作。
Svartalf

11

扩展评论之一,我不认为您在做自己认为在做的事情。

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

$ 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 -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

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

6

与我-delete相比,我有机会进行测试-exec rm \{\} \;,对我来说-delete,这就是答案。

使用-delete删除了400,000个文件的文件夹中的文件,速度比至少快1000倍rm

“如何在linux中删除大量文件”一文表明它的速度快了大约三倍,但在我的测试中,差异要大得多。


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

5

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

find . -ls -exec rm {} \;

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

find . -delete

相反,我现在就让它运行。它看起来运行得更快,尽管它在CPU上的工作非常繁重,而其他命令却没有。它已经运行了大约一个小时,我想我的驱动器上的空间已经恢复了,分区逐渐“减少”,但是仍然需要很长时间。我严重怀疑它的运行速度比其他设备快1000倍。在所有情况下,我只想指出空间与时间之间的权衡。如果您有多余的CPU带宽(我们愿意),请运行后者。我的CPU正在运行(uptime报告):

10:59:17 up 539 days, 21:21,  3 users,  load average: 22.98, 24.10, 22.87

而且我已经看到平均负载超过30.00,这对于繁忙的系统而言并不好,但是对于我们通常负载较轻的系统而言,可以持续几个小时。我已经检查了系统上的大多数其他内容,但它们仍然可以响应,因此我们现在可以了。


如果您要使用exec,则几乎可以肯定不使用,-ls而do find . -type f -exec rm '{}' ++会更快,因为它将为rm提供尽可能多的参数。
xenoterracide 2014年

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

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

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


3

考虑使用Btrfs卷,并仅删除具有大量文件的目录的整个卷。

另外,您可以创建一个FS映像文件,然后卸载并删除其文件,以非常快的方式一次删除所有内容。


2

假设已经parallel安装了GNU ,我使用了以下方法:

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

而且速度足够快。


1

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

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

5
使用+代替\;会更快,因为它可以一次将更多的参数传递给rm,减少分叉
xenoterracide 2014年

1
为什么不呢 ionice -c3 find <dir> -type f -delete
jtgd

0
ls -1 | xargs rm -rf 

应该在主文件夹中工作


1
ls由于该文件夹中的文件数量大而无法使用。这就是为什么我不得不使用find,但是谢谢。
Toby 2012年

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

1
不适用于包含换行符的文件名。
maxschlepzig 2014年

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

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

0

对于上述Izkata的提示:

但这确实有效:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

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


0

根据您需要如何删除这些文件,我建议使用shred

$ shred -zuv folder

如果您要清除目录,但是无法删除它并重新创建它,建议您移动它并立即重新创建它。

mv folder folder_del
mkdir folder
rm -rf folder_del

不管您是否相信,这都更快,因为只需要更改一个inode。切记:您无法真正在多核计算机上并行化此测试。它取决于磁盘访问,这受RAID或您所拥有的东西的限制。


1
shred 不适用于许多现代文件系统。

0

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

档案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($1)}') -gt $MAX_LOAD ]]; do
        echo -n "."
        sleep 1
    done
done

现在删除文件:

find /path/to/folder -type f -exec ./nice_delete {} \+

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


0

如果您只是想尽快清除许多文件,则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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.