web-dev-qa-db-ja.com

大量のファイルを削除するより速い方法

多くのキャッシュされたファイルが非常に迅速に生成されるディレクトリがあります。これらは非常に小さなファイルであるため、すべてのiノードが非常に速く消費されます。

現在、私は次のコマンドを実行して、12時間以上経過したすべてのファイルを見つけて削除しています。

$ find ./cache -mtime +0.5 -exec rm {} \;

ただし、このコマンドが削除する速度は、ファイルが生成される速度よりも遅くなります。誰かが大量のファイルをすばやく削除する別の方法を教えてもらえますか?.

11
pradeepchhetri

xargsを使用してみてください:

find ./cache -mtime +0.5 -print0 | xargs -0 rm -f

@ pradeepchhetriの説明を更新

find-execとともに使用すると、findが検出したすべてのファイルがrmを1回呼び出します。したがって、大量のファイル、つまり10000ファイルを見つけた場合、rmを10000回呼び出しました。

xargsは、findの出力をrmへのコマンド引数として扱うため、xargsはrmが一度に処理できる数の引数を提供します。つまり、rm -f file1 file2 ...したがって、フォークの呼び出しが少なくなり、プログラムの実行が速くなります。

17
cuonglm

find … -exec rm {} \;は、各ファイルに対してrmコマンドを実行します。新しいプロセスの開始はかなり高速ですが、それでもファイルを削除するという単なる動作よりもはるかに低速です。

find … -exec rm {} +rmをバッチで呼び出すため、はるかに高速です。バッチごとにrmを実行するコストを支払うと、各バッチで多数の削除が実行されます。

さらに高速なのは、rmをまったく呼び出さないことです。 Linuxのfindコマンドにはアクション-delete一致するファイルを削除します。

find ./cache -mtime +0.5 -delete

ただし、そのような速度でファイルを作成している場合、find … -exec rm {} \;に対応できません。設定に問題がある可能性があります。 cacheに数百万のファイルが含まれている場合は、アクセスを高速化するために、ファイルをサブディレクトリに分割する必要があります。

作成率が削除率を超える場合は、キャッシュを完全に空にし、mtime評価なしで古いファイルを削除するのが最善です。

mv cache foobar
mkdir cache
# may require app restart
rm -rf foobar
2
kerolasa

Findは最良の(最も単純で慣用的な)アプローチですが、

find $dir -exec rm {} +

ディレクトリを脇に移動し、(プログラム用に)新しいディレクトリを作成してから、削除することができます...

mv $idr old$dir && mkdir $dir && rm -rf old$dir

しかし、おそらくあなたの問題は、あまりにも多くのファイルを作成することです。新しいファイルを作成するのではなく、既存のファイルに追加するようにプログラムを変更しませんか?次に、この(ログファイル)を脇に移動し、プログラムで新しいファイルを作成/追加できます。たとえば、

fd = open("logfile","a+");
1
ChuckCottrill

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

別のLinux固有のソリューションは inotify(7) 機能を使用することです。ファイルが追加されたことを検出し、すぐに何かを実行して古いファイルを削除します。

OTOH、あなたはいくつかの XY問題 を持っていると思います。新しいファイルがたくさんあるのはなぜですか?おそらく、sqlite、またはGDBMインデックス付きファイル、またはいくつかの実際のデータベース(PostGresQL、MariaDB、MongoDBなど)を使用する方が良いかもしれません。おそらく、 git

rm -rf directory /は、1つのフォルダー内の数十億のファイルに対しても高速に動作します。やってみました。