セントOS 5.9
最近、ディレクトリに多くのファイルがある問題に遭遇しました。計算するために走ったls -l /foo/foo2/ | wc -l
単一のディレクトリに100万を超えるファイルがあることがわかりました(長いストーリー - 根本的な原因が解決されています)。
私の質問は:計算を実行するより速い方法はありますか?カウントを取得する最も効率的な方法は何ですか?
ベストアンサー1
短い答え:
\ls -afq | wc -l
(ここには.
合計が含まれているので..
2を引いてください。)
ディレクトリ内のファイルを一覧表示すると、3つの一般的な状況が発生する可能性があります。
- ディレクトリのファイル名を列挙します。これは避けられないことです。ファイルを列挙しないと、ディレクトリ内のファイルの数を数えることはできません。
- ファイル名をソートします。シェルワイルドカードと
ls
コマンドを使用してこれを実行できます。 - 呼ぶ
stat
ディレクトリかどうかなど、各ディレクトリエントリのメタデータを検索します。
#3は各ファイルに対してinodeをロードする必要があるため、最も費用がかかります。対照的に、#1に必要なすべてのファイル名はいくつかのブロックにコンパクトに保存されます。 #2は少しCPU時間を無駄にしますが、一般的に取引の中断要因ではありません。
ファイル名に改行文字が含まれていない場合は、ls -A | wc -l
ディレクトリにファイルがいくつあるかを単に通知します。エイリアスがある場合はls
呼び出しがトリガーされる可能性があるためstat
(たとえば、呼び出しが必要なls --color
ファイルls -F
形式を知る必要があるためstat
)、コマンドラインから呼び出すか、command ls -A | wc -l
エイリアス\ls -A | wc -l
を避けてください。
ファイル名に改行がある場合、改行を表示するかどうかはUnixのバリエーションによって異なります。 GNU coreutils と BusyBox は?
デフォルトで改行を表示するので安全です。
ls -f
アイテムをソートせずにリストするために呼び出されます(#2)。これは自動的にオンになります-a
(少なくとも最新のシステムでは)。この-f
オプションは POSIX にありますが、オプションの状態です。ほとんどの実装はこれをサポートしますが、BusyBoxはサポートしません。このオプションは、-q
印刷できない文字(改行を含む)に置き換えます?
。これはPOSIXですが、BusyBoxではサポートされていません。したがって、BusyBoxのサポートが必要な場合は、名前に改行を含むファイルの数を犠牲にして無視してください。
ディレクトリにサブディレクトリがない場合、ほとんどのバージョンはそのエントリをfind
呼び出しませんstat
(リーフディレクトリの最適化:リンク数が2のディレクトリはサブディレクトリを持つことができないため、find
条件で要求されない限りエントリのメタデータを検索する必要はありません-type
) 。これはfind . | wc -l
、ディレクトリにサブディレクトリがなく、ファイル名に改行文字が含まれていない場合にディレクトリ内のファイル数を数える移植可能で高速な方法です。
ディレクトリにサブディレクトリはありませんが、ファイル名に改行文字を含めることができる場合は、次のいずれかを試してください。サポートされている場合は、2番目のディレクトリが速くなりますが、目立たないことがあります。
find -print0 | tr -dc \\0 | wc -c
find -printf a | wc -c
一方、find
ディレクトリにサブディレクトリがある場合:を使用しないでください。または、各項目をfind . -maxdepth 1
呼び出すこともできますstat
(少なくともGNU検索とBusyBox検索を使用)。ソート(#2)は回避できますが、inodeルックアップ(#3)が発生し、パフォーマンスが低下します。
外部ツールのないシェルでは、.runを使用して現在のディレクトリのファイル数を計算できますset -- *; echo $#
。これはドットファイル(名前で始まるファイル.
)を見逃し、空のディレクトリに0の代わりに1を報告します。これは、外部プログラムを起動する必要がないため、小さなディレクトリ内のファイル数を数える最速の方法ですが(zshを除く)、ソートステップ(#2)により、より大きなディレクトリに時間を無駄にします。
Bashでは、これは現在のディレクトリのファイル数を計算する安定した方法です。
shopt -s dotglob nullglob a=(*) echo ${#a[@]}
ksh93では、これは現在のディレクトリのファイル数を計算する安定した方法です。
FIGNORE='@(.|..)' a=(~(N)*) echo ${#a[@]}
zshでは、これは現在のディレクトリのファイル数を計算する安定した方法です。
a=(*(DNoN)) echo $#a
このオプションを設定した場合は、その
mark_dirs
オプションをオフにする必要があります。a=(*(DNoN^M))
。すべてのPOSIXシェルでは、これは現在のディレクトリのファイル数を数える安定した方法です。
total=0 set -- * if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi set -- .[!.]* if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi set -- ..?* if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi echo "$total"
zshを除いて、これらのメソッドはすべてファイル名をソートします。