数百万のファイルがあるファイルシステムがあり、特定のディレクトリでファイルサイズを再帰的に分散させたいと考えています。これはbash/awk fuで完全に実行できるように感じますが、手を使用することもできます。基本的に私は次のようなものが欲しいです:
1KB: 4123
2KB: 1920
4KB: 112
...
4MB: 238
8MB: 328
16MB: 29138
Count: 320403345
ループといくつかの条件付きlog2ファイルサイズfooがあれば、これはそれほど悪くないはずだと思いますが、そこに到達することはまったくできないようです。
関連する質問: xバイトよりも大きい/小さいファイルを見つけるにはどうすればよいですか? 。
これはかなりうまくいくようです:
find . -type f -print0 | xargs -0 ls -l | awk '{size[int(log($5)/log(2))]++}END{for (i in size) printf("%10d %3d\n", 2^i, size[i])}' | sort -n
その出力は次のようになります。
0 1
8 3
16 2
32 2
64 6
128 9
256 9
512 6
1024 8
2048 7
4096 38
8192 16
16384 12
32768 7
65536 3
131072 3
262144 3
524288 6
2097152 2
4194304 1
33554432 1
134217728 4
Garyjohnの回答に基づいて、出力を人間が読める形式にフォーマットするワンライナーを次に示します。
_find . -type f -print0 | xargs -0 ls -l | awk '{ n=int(log($5)/log(2)); if (n<10) { n=10; } size[n]++ } END { for (i in size) printf("%d %d\n", 2^i, size[i]) }' | sort -n | awk 'function human(x) { x[1]/=1024; if (x[1]>=1024) { x[2]++; human(x) } } { a[1]=$1; a[2]=0; human(a); printf("%3d%s: %6d\n", a[1],substr("kMGTEPYZ",a[2]+1,1),$2) }'
_
これがその拡張バージョンです:
_find . -type f -print0 \
| xargs -0 ls -l \
| awk '{ n=int(log($5)/log(2)); \
if (n<10) n=10; \
size[n]++ } \
END { for (i in size) printf("%d %d\n", 2^i, size[i]) }' \
| sort -n \
| awk 'function human(x) { x[1]/=1024; \
if (x[1]>=1024) { x[2]++; \
human(x) } } \
{ a[1]=$1; \
a[2]=0; \
human(a); \
printf("%3d%s: %6d\n", a[1],substr("kMGTEPYZ",a[2]+1,1),$2) }'
_
最初のawk
では、1kb未満のすべてのファイルを1か所に収集するための最小ファイルサイズを定義しました。 2番目のawk
では、関数human(x)
が定義され、人間が読めるサイズを作成します。この部分は、ここでの回答の1つに基づいています: https://unix.stackexchange.com/questions/44040/a-standard-tool-to-convert-a-byte-count-into-human-kib -mib-etc-like-du-ls1
サンプル出力は次のようになります。
_ 1k: 335
2k: 16
32k: 5
128k: 22
1M: 54
2M: 11
4M: 13
8M: 3
_
これを試して:
_find . -type f -exec ls -lh {} \; |
gawk '{match($5,/([0-9.]+)([A-Z]+)/,k); if(!k[2]){print "1K"} \
else{printf "%.0f%s\n",k[1],k[2]}}' |
sort | uniq -c | sort -hk 2
_
出力:
_ 38 1K
14 2K
1 30K
2 62K
12 2M
2 3M
1 31M
1 46M
1 56M
1 75M
1 143M
1 191M
1 246M
1 7G
_
説明:
_find . -type f -exec ls -lh {} \;
_:簡単です。現在のディレクトリでファイルを見つけて、それらに対して_ls -lh
_を実行します。
match($5,/([0-9.]+)([A-Z]+)/,k);
:これにより、ファイルサイズが抽出され、一致するものがそれぞれ配列k
に保存されます。
if(!k[2]){print "1K"}
:_k[2]
_が未定義の場合、ファイルサイズは<1Kです。このような小さなサイズは気にしないと思いますので、スクリプトはサイズが<= 1Kのすべてのファイルに対して_1K
_を出力します。
_else{printf "%.0f%s\n",k[1],k[2]}
_:ファイルが1Kより大きい場合は、ファイルサイズを最も近い整数に丸め、その修飾子(K、M、またはG)とともに出力します。
_sort | uniq -c
_:印刷された各行(ファイルサイズ)の出現回数をカウントします。
_sort -hk 2
_:人間が読める形式の2番目のフィールドに従って並べ替えます。このように、_7G
_は_8M
_の後にソートされます。