数千のファイルを含む大きなディレクトリを効率的に削除する


162

フォルダーが数十万の小さなファイルで扱いにくくなるという問題があります。

実行rm -rfするとエラーが返されるファイルが非常に多いため、代わりに次のようにする必要があります。

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

これは機能しますが、非常に遅く、メモリ不足により常に失敗します。

これを行うためのより良い方法はありますか?理想的には、ディレクトリ内のコンテンツを気にせずにディレクトリ全体を削除したいと思います。


16
rm -rf *引数が多すぎるため、フォルダ内で失敗する可能性があります。しかし、rm -rf folder/とにかくディレクトリ全体を削除したい場合はどうでしょうか?
sr_

4
手動で削除する代わりに、フォルダを別のパーティションに置き、単に&&フォーマット&&再マウントすることをお勧めします。
bbaja42

7
好奇心から-いくつのファイルが壊れるのrm -rfですか?
jw013

7
おそらく、「数千のファイルを含む大きなディレクトリを効率的に削除する」など、質問の名前をより正確なものに変更する必要があります。ディレクトリその内容を削除するには、定義により再帰が必要です。ディレクトリiノード自体のみを手動でリンク解除し(おそらくルート権限が必要です)、ファイルシステムをアンマウントし、そのfsck上で実行して未使用のディスクブロックを再利用できますが、このアプローチは危険で、高速ではない場合があります。さらに、ファイルシステムチェックには、ファイルシステムツリーの再帰的な走査が含まれる場合があります。
jw013

4
私が持っていたらccache、ファイルツリーがとても巨大な、とrmそう長く取って(とシステム全体が低迷すること)して、それはファイルシステムからすべての他のファイルをコピーするにはかなり速かった、フォーマット、およびそれらをコピーバック。それ以来、私は、このような大規模な小さなファイルの木にそれぞれ専用のファイルシステムを与えるので、あなたのことができmkfsなく直接のrm
frostschutz

回答:


213

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を使用していますが、このように削除するために使用できるとは思いもしませんでした。rm -rfよりも非常に速い
ジョンパウエル14

22
rsyncrm削除が正しい順序で行われることを保証するため、plainよりも高速になり、必要な再計算が少なくなります。この回答を参照してくださいserverfault.com/a/328305/105902
Marki555

7
誰でもperl式を変更して、directory_to_be_deleted内のすべてのディレクトリとファイルを再帰的に削除できますか?
アビナフ

5
注:-Prsyncにオプションを追加して表示を増やします。また、構文に注意してください。末尾のスラッシュ必須です。最後に、-n最初にオプションrun with runを起動して、rsyncコマンドを初めて起動できます
ドラシル

1
-a等しい-rlptgoDが、削除のみ-rdが必要
Koen。

38

上の誰かTwitterは使用して提案-deleteの代わりに、-exec rm -f{} \;

これにより、コマンドの効率が向上しましたが、再帰を使用してすべてを処理しています。


11
これは非標準です。GNU findhave -delete、およびその他のfind多分。
-enzotib

13
-delete-exec rm安全性と効率性の理由から、利用可能な場合よりも常に優先されるべきです。
jw013

6
GNUは事実上の標準です。
ロンジョン

17

次のようなものはどうですか: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

parameterの引数を変更すると、一度に削除するファイルの数を制限できます-n。空白のあるファイル名も含まれます。


2
-n 20xargsは、とにかく許容可能な引数リストのサイズに制限されるため、おそらくビットは必要ありません。
役に立たない

はい、あなたは正しいです。以下からのメモです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

12

巧妙なトリック:

rsync -a --delete empty/ your_folder/

CPUを集中的に使用しますが、本当に高速です。https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.htmlを参照してください


ディレクトリの内容を非効率的に読み取るため、それほど高速ではありません。10倍の高速化ソリューションと説明については、この答えを参照してくださいserverfault.com/a/328305/105902
Marki555

2
@ Marki555:質問の編集では、の場合は60秒、の場合はrsync -a --delete43 秒と報告されlsdentます。比率10xはtime ls -1 | wc -l vs でした time ./dentls bigfolder >out.txt> filevsのために部分的に公平な比較です wc -l)。
ハスター

問題があることがあるNONEあそこのコマンドが実際に行わない削除のために必要なトラバーサル操作を。彼らが与えるコードは?Marki555の説明どおりに機能しません。
スヴァルタルフ

11

コメントの1つを拡大すると、あなたがしていると思うことをしているとは思わない。

最初に、状況をシミュレートするために大量のファイルを作成しました。

$ 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。数回実行します。数千万のサブディレクトリとファイルを含むディレクトリがありました。私も実行できませんでしたlsか、findまたはrsyncそれがメモリを使い果たしたので、そのディレクトリに。このコマンドrm -Rfは何度も(メモリ不足で)終了し、数十億のファイルの一部のみを削除します。しかし、多くの再試行の後、最終的に仕事をしました。メモリ不足が問題である場合、唯一の解決策のようです。
エリック14

6

これに-delete比べてテストする機会が-exec rm \{\} \;あり、私にとって-deleteはこの問題に対する答えでした。

を使用-deleteして、400,000ファイルのフォルダー内のファイルを削除しますrm

「Linuxで大量のファイルを削除する方法」の記事では、約3倍高速であることが示唆されていますが、私のテストでは、その差ははるかに劇的でした。


3
を使用find -execすると、rmすべてのファイルに対して個別にコマンドが実行されるため、非常に遅いです。
Marki555

5

-delete上記のオプションについて:作成した一時フォルダー内の多数(1M + est)のファイルを削除するために使用しており、誤って毎晩クリーンアップするのを忘れていました。誤ってディスク/パーティションをいっぱいにしたが、find .コマンド以外はそれらを削除できなかった。遅いです、最初は私が使っていました:

find . -ls -exec rm {} \;

しかし、それは非常に時間がかかっていました。いくつかのファイルを削除するために約15分後に開始されましたが、私の推測では、最終的に開始してから1秒あたり10個以下しか削除していなかったようです。だから、私は試しました:

find . -delete

代わりに、今すぐ実行させています。他のコマンドでは実行できなかったCPUに非常に負荷がかかっていますが、実行速度は速いようです。現在1時間ほど稼働しており、ドライブのスペースを取り戻していると思います。パーティションは徐々に「スリム化」しますが、それでも非常に長い時間がかかります。私は、それが他のものより1,000倍速く走ることを真剣に疑います。すべてのものと同様に、空間と時間のトレードオフを指摘したかっただけです。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

先に進んでこれを独自の回答に編集する必要があると思います。コメントするには長すぎます。また、あなたのファイルシステムはかなり高価な削除を持っているように聞こえますが、それはどれですか?またはをfind … -delete介して実行できます。そのため、一部のマウントオプションをクラッシュセーフでない設定に変更する場合があります。(そして、もちろん、ファイルシステムに他に何があるかにもよりますが、すべてを削除する最も簡単な方法はしばしばです。)niceionicemkfs
デロバート14年

3
負荷平均は常にCPUであるとは限りません。これは、ブロックされたプロセスの時間の単なる尺度です。プロセスはディスクI / Oでブロックする可能性がありますが、これはおそらくここで起こっていることです。
Score_Under

また、負荷平均は論理CPUの数を考慮しないことに注意してください。その1ため、シングルコアマシンのloadavg は、6464コアシステムのloadavgと同じです。つまり、各CPUは100%時間ビジーです。
Marki555

3

Linuxで多数のファイルを削除するために使用できる方法がいくつかあります。findオプションとdeleteオプションを使用できます。これは、execオプションよりも高速です。次に、perl unlinkを使用し、さらにrsyncを使用できます。 Linuxで大量のファイルを削除する方法


3

Btrfsボリュームの使用を検討し、多数のファイルがあるディレクトリのボリューム全体を単純に削除します。

または、FSイメージファイルを作成し、そのファイルをアンマウントして削除し、すべてを一度に非常に高速に削除することもできます。


2

GNUがparallelインストールされていると仮定して、私はこれを使用しました:

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

そしてそれは十分に速かった。


1

このサイトから学んだように、本当に大きなディレクトリを削除するには別のアプローチ が必要です-ioniceを使用する必要があります(-c3を使用すると)システムにIO時間がある場合にのみ削除が実行されます。システムの負荷が高くなることはなく、すべての応答性は維持されます(ただし、findのCPU時間は約50%と非常に高くなりました)。

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

5
使用する+代わりにすることは\;、それが一度にRMために複数の引数を渡すように、これはより速くより少ないフォークになるだろう
xenoterracide

1
理由はありません ionice -c3 find <dir> -type f -delete
-jtgd

0
ls -1 | xargs rm -rf 

メインフォルダ内で動作するはずです


1
lsフォルダー内のファイルの量が原因で機能しません。だからこそ、私は使用しなければならなかったのですfind、ありがとう。
トビー

4
@Toby:Try ls -f、並べ替えを無効にします。ソートを行うには、ディレクトリ全体をソートしてメモリにロードする必要があります。ソートされていないものlsは、その出力をストリーミングできる必要があります。
-camh

1
改行を含むファイル名では機能しません。
maxschlepzig 14年

@camhそれは本当です。ただし、ソートされた順序でファイルを削除する方が、ソートされていない場合よりも高速です(削除ごとにディレクトリのbtreeを再計算するため)。例のために、この答えを参照してくださいserverfault.com/a/328305/105902
Marki555

@maxschlepzigを使用するとfind . -print0 | xargs -0 rm、ファイル名の区切り文字としてNULL文字が使用されます。
Marki555

0

上記のIzkataのヒント:

しかし、これ機能します:

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

これはほとんど機能しました-または機能していました-しかし、私は許可にいくつかの問題がありました。ファイルはサーバー上にありましたが、この許可の問題の原因はまだわかりません。とにかく、ターミナルはすべてのファイルで確認を求めました。ファイルの量は約20 000だったので、これはオプションではありませんでした。「-r」の後にオプション「-f」を追加したため、コマンド全体は「rm -r -f foldername /」になりました。それからそれはうまくいくように見えた。私はターミナルの初心者ですが、これは大丈夫でしたね。ありがとう!


0

これらのファイルを削除する必要があるかどうかに応じて、を使用することをお勧めしshredます。

$ shred -zuv folder

ディレクトリを削除したいが、削除して再作成できない場合は、移動してすぐに再作成することをお勧めします。

mv folder folder_del
mkdir folder
rm -rf folder_del

変更する必要があるのは1つのiノードだけなので、これは信じられないかもしれませんが、より高速です。要確認:マルチコアコンピューターでは、このテイストを実際に並列化することはできません。それはディスクアクセスに帰着します。これは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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.