非常に多数のファイル(100,000を超える)がある場合に、特定のディレクトリ内のファイルの数を見つけるための最良の方法を見つけようとしています。
ファイルが多い場合、実行ls | wc -l
にかなりの時間がかかります。これは、すべてのファイルの名前が返されるためだと思います。ディスクI/Oをできるだけ少なくしようとしています。
私はいくつかのシェルとPerlスクリプトを試しましたが無駄になりました。どうすればいいですか?
40,000 個のファイルに対してテストされたfind、ls、およびperlは同じ速度です (ただし、キャッシュをクリアしようとしませんでした)。
[user@server logs]$ time find . | wc -l
42917
real 0m0.054s
user 0m0.018s
sys 0m0.040s
[user@server logs]$ time /bin/ls -f | wc -l
42918
real 0m0.059s
user 0m0.027s
sys 0m0.037s
Perl のopendirとreaddirを同時に使用すると、次のようになります。
[user@server logs]$ time perl -e 'opendir D, "."; @files = readdir D; closedir D; print scalar(@files)."\n"'
42918
real 0m0.057s
user 0m0.024s
sys 0m0.033s
注: /bin/ls -f を使用して、少し遅くなる可能性があるエイリアス オプションを確実にバイパスし、-f
ファイルの順序付けを回避しました。
ls
withoutは/-f
よりも 2 倍遅くなりますが、 が と一緒に使用されている
場合を除き、同じ時間のようです:find
perl
ls
-f
[user@server logs]$ time /bin/ls . | wc -l
42916
real 0m0.109s
user 0m0.070s
sys 0m0.044s
また、不要な情報を一切表示せずにファイル システムに直接問い合わせるスクリプトも必要です。
テストは、 Peter van der Heijden、glenn jackman、およびmark4oの回答に基づいています。
驚くべきことに、必要最小限の検索は ls -f に非常に匹敵します。
> time ls -f my_dir | wc -l
17626
real 0m0.015s
user 0m0.011s
sys 0m0.009s
対
> time find my_dir -maxdepth 1 | wc -l
17625
real 0m0.014s
user 0m0.008s
sys 0m0.010s
もちろん、小数第 3 位の値は、これらのいずれかを実行するたびに少しずつ変化するため、基本的には同じです。ただし、実際のディレクトリ自体をカウントするため、余分な単位が 1 つ返されることに注意してくださいfind
(また、前述のように、ls -f
. と .. もカウントするため、余分な単位が 2 つ返されます)。
要件に基づいて出力を変更できますが、これは私が作成した Bash のワンライナーで、一連の数値的に名前が付けられたディレクトリ内のファイル数を再帰的にカウントして報告します。
dir=/tmp/count_these/ ; for i in $(ls -1 ${dir} | sort -n) ; { echo "$i => $(find ${dir}${i} -type f | wc -l),"; }
これは、指定されたディレクトリ内のすべてのファイル (ディレクトリではない) を再帰的に検索し、結果をハッシュのような形式で返します。find コマンドを微調整するだけで、どのような種類のファイルを探しているかをより具体的にすることができます。
次のような結果になります。
1 => 38,
65 => 95052,
66 => 12823,
67 => 10572,
69 => 67275,
70 => 8105,
71 => 42052,
72 => 1184,
ls
ファイル名のソートにより多くの時間を費やします。並べ替えを無効にするために使用-f
します。これにより、時間を節約できます。
ls -f | wc -l
または、次を使用できますfind
。
find . -type f | wc -l
treeプログラムを使用して、ファイルとディレクトリの数を取得できます。
コマンドtree | tail -n 1
を実行して、「763 個のディレクトリ、9290 個のファイル」のような最後の行を取得します。これは、フラグで追加できる隠しファイルを除いて、ファイルとフォルダーを再帰的にカウントします-a
。参考までに、私のコンピューターでは、tree がホーム ディレクトリ全体をカウントするのに 4.8 秒かかりました。これは、24,777 ディレクトリ、238,680 ファイルでした。5.3 秒かかり、0.5 秒長くなったので、 treeは速度的にかなり競争力があるfind -type f | wc -l
と思います。
サブフォルダーがない限り、ツリーはファイルを数えるための迅速かつ簡単な方法です。
また、純粋に楽しみのためにtree | grep '^├'
、現在のディレクトリ内のファイル/フォルダーのみを表示するために を使用できます。これは基本的に のはるかに遅いバージョンですls
。
それぞれ約 10,000 個のファイルを含む約 10,000 個のフォルダーのデータ セット内のファイルをカウントしようとしたときに、ここに来ました。多くのアプローチの問題は、1 億個のファイルを暗黙のうちに統計することであり、これにはかなりの時間がかかります。
Christopher Schultz によるアプローチを自由に拡張して、引数によるディレクトリの受け渡しをサポートするようにしました (彼の再帰的アプローチではstatも使用されます)。
以下を file に入れますdircnt_args.c
:
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[]) {
DIR *dir;
struct dirent *ent;
long count;
long countsum = 0;
int i;
for(i=1; i < argc; i++) {
dir = opendir(argv[i]);
count = 0;
while((ent = readdir(dir)))
++count;
closedir(dir);
printf("%s contains %ld files\n", argv[i], count);
countsum += count;
}
printf("sum: %ld\n", countsum);
return 0;
}
a の後、次のgcc -o dircnt_args dircnt_args.c
ように呼び出すことができます。
dircnt_args /your/directory/*
10,000 個のフォルダーに 1 億個のファイルがある場合、上記は非常に短時間で完了します (最初の実行で約 5 分、キャッシュでのフォローアップ: 約 23 秒)。
1時間以内に終了した唯一の他のアプローチはls
、約 1 分のキャッシュでした: ls -f /your/directory/* | wc -l
. ただし、ディレクトリごとに数行の改行がずれています...
予想外に、私の試みはfind
1時間以内に返されませんでした:-/
opendir()
and readdir()
inを使用するPerl
方が速いかどうかを試すことができます。これらの機能の例については、こちらをご覧ください。
大量のデータがある場合、メモリ処理を使用しない方が、コマンドを「パイプ」するよりも高速であることに気付きました。そのため、結果をファイルに保存し、後で分析しました。
ls -1 /path/to/dir > count.txt && wc-l count.txt
ファイル数が最も多い最初の 10 個のディレクトリ。
dir=/ ; for i in $(ls -1 ${dir} | sort -n) ; { echo "$(find ${dir}${i} \
-type f | wc -l) => $i,"; } | sort -nr | head -10
ディレクトリ内のファイル数の変化を追跡するには、次のコマンドを使用することをお勧めします。
watch -d -n 0.01 'ls | wc -l'
このコマンドは、0.1 秒のリフレッシュ レートでディレクトリ内にあるファイルの数を追跡するために、ウィンドウを開いたままにします。