web-dev-qa-db-ja.com

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

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

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

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

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

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

177
Toby

Rsyncの使用は驚くほど速くて簡単です。

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

@sarathの答えは、もう1つの速い選択である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
238
stevendaniels

Twitter の誰かが-delete の代わりに -exec rm -f{} \;

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

42
Toby

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

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

19

巧妙なトリック:

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

16
MZAweb

コメントの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
14
Izkata

-deleteと比較して-exec rm \{\} \;をテストする機会があり、-deleteがこの問題の答えでした。

-deleteを使用すると、40万ファイルのフォルダー内のファイルがrmより少なくとも1,000倍高速に削除されました。

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

10
user2365090

上記の-deleteオプションについて:作成した一時フォルダ内の大量の(100万以上の)ファイルを誤って削除し、誤って毎晩クリーンアップするのを忘れていました。誤ってディスク/パーティションをいっぱいにしてしまい、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を超えるのを見たことがありますが、これはビジーなシステムには適していませんが、通常は負荷が軽いため、数時間は問題ありません。私はシステム上の他のほとんどのものをチェックしましたが、それらはまだ反応しているので、今のところ大丈夫です。

5
Scotty

Btrfsボリュームの使用を検討し、多数のファイルがあるこのようなディレクトリのボリューム全体を削除してください。

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

4
Sergei

rm -rf directoryの代わりにrm -rf *を使用してください。

内容をクリアするためにディレクトリにいる間、私たちは最初にrm -rf *を行っていましたが、それは可能な限り速いと考えました。しかし、それから 上級エンジニア の1人がアスタリスク(*)の使用を避け、代わりにrm -rf directoryのような親ディレクトリを渡すことを提案しました。

それが違いを生まない方法についての激しい議論の後、findを使用する3番目の方法とともに、それをベンチマークすることにしました。結果は次のとおりです。

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

rm -rf directoryrm -rf *よりも約9倍高速です!

言うまでもなく、私たちは あのエンジニア ビールを買いました!

そのため、rm -rf directory; mkdir directoryを使用してディレクトリを削除し、再作成します。

4
Joshua Pinter

Linuxで多数のファイルを削除するために使用できる方法がいくつかあります。 execオプションよりも高速な、find with deleteオプションを使用できます。その後、Perlのリンク解除、さらにはrsyncを使用できます。 Linuxで多数のファイルを削除する方法

4
sarath

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

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

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

2
Nacho

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

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

数百万のファイルがあり、上記のすべての解決策でシステムにストレスがかかる場合は、次のインスピレーションを試すことができます。

ファイル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に渡します。これにより、さらに小さなバッチが作成され、過負荷が検出されたときにスリープできるようになります。

1
brablc

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

$ shred -zuv folder

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

mv folder folder_del
mkdir folder
rm -rf folder_del

変更する必要があるのは1つのiノードだけなので、これはより速く、信じられないかもしれません。覚えておいてください。マルチコアコンピューターでは、この味を実際に並列化することはできません。それは、RAIDまたはあなたが持っているものによって制限されるディスクアクセスに帰着します。

0
polemon

Pythonスクリプトは不潔なものとして排除すべきではありません。

#!/usr/bin/python3

import shutil
path_for_deletion = input( 'path of dir for deletion> ' ) 
print( 'about to remove ' + path_for_deletion + ' ...' )
shutil.rmtree( path_for_deletion, ignore_errors=True )
print( '... done' )

私は、さまざまな方法のいくつかの有用なベンチマークを行った人 here にこれをベンチマークしてみることができるかどうか尋ねました。私の実験から、それはかなり良いようです。

NBエラーは、少なくともそれらを出力するために処理できますが、後でtrash myDirectoryForDeletionまたはrm -rfv myDirectoryForDeletionを実行する方が簡単な場合があります。

0
mike rodent

できるだけ早く多くのファイルを削除したい場合は、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
0
Leon Kramer

上記のイズカタのヒント:

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

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

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

0
user41527
ls -1 | xargs rm -rf 

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

0
PsyStyle

使用する ls -f | xargs -n 5000 rm、調整中-nシステムに応じたバッチサイズ(_digital_infinityのkudosは-n ヒント)。

さらに、インラインgrepを使用してリストをフィルタリングできます。 ls -f | grep '^156' | xargs -n 5000 rm

私の経験では、これはfindを使用する手法よりもはるかに高速で、より複雑なシェルスクリプトの必要性を排除します。

0
buckaroo1177125