私の現在の解決策は ですがfind <expr> -exec printf '.' \; | wc -c
、結果が 10000 件を超えると時間がかかりすぎます。これを行うためのより速い/より良い方法はありませんか?
6 に答える
なぜだめですか
find <expr> | wc -l
シンプルなポータブルソリューションとして? 元の解決策は、見つかった個々のファイルごとに新しいプロセスを生成することであり、これは非常に高価です (先ほど見つけたように)。 printf
改行が埋め込まれたファイル名がある場合、これは過大評価されることに注意してください。
代わりにこれを試してください (find
の-printf
サポートが必要です):
find <expr> -type f -printf '.' | wc -c
行を数えるよりも信頼性が高く、高速です。
外部コマンドではなく、find
'sを使用していることに注意してください。printf
少しベンチに立ちましょう :
$ ls -1
a
e
l
ll.sh
r
t
y
z
私のスニペットベンチマーク:
$ time find -type f -printf '.' | wc -c
8
real 0m0.004s
user 0m0.000s
sys 0m0.007s
実線あり:
$ time find -type f | wc -l
8
real 0m0.006s
user 0m0.003s
sys 0m0.000s
したがって、私のソリューションはより高速です=)(重要な部分はreal
行です)
このソリューションは、ここにある他のソリューションのいくつかよりも確かに遅いfind -> wc
ですが、ファイル名をカウントすることに加えて、ファイル名で何か他のことをしたい場合はread
、出力から行うことができfind
ます.
n=0
while read -r -d ''; do
((n++)) # count
# maybe perform another act on file
done < <(find <expr> -print0)
echo $n
を使用して出力区切り文字を NUL バイトにし、ループ区切り文字として (NUL バイト)を使用して読み取ることにより、標準外の名前のファイルを適切に処理する BashGuideにあるソリューションの変更にすぎません。find
print0
''
これは私のcountfiles
関数です~/.bashrc
(かなり高速で、 Linux および FreeBSDfind
で動作するはずであり、改行文字を含むファイルパスにだまされません。最終的wc
には NUL バイトをカウントするだけです):
countfiles ()
{
command find "${1:-.}" -type f -name "${2:-*}" -print0 |
command tr -dc '\0' | command wc -c;
return 0
}
countfiles
countfiles ~ '*.txt'
他のいくつかのコマンドも印刷物を実行するため、findからすべての出力を取得しないものが必要でした。
一時ファイルを必要としない場合、これは大きな注意点がある場合にのみ可能です: 800~1600 ファイルごとに 1 回出力コマンドを実行するため、(はるかに) 複数行の出力が得られる可能性があります。
find . -print -exec sh -c 'printf %c "$@" | wc -c' '' '{}' + # just print the numbers
find . -print -exec sh -c 'echo "Processed `printf %c "$@" | wc -c` items."' '' '{}' +
次の結果が生成されます。
Processed 1622 items.
Processed 1578 items.
Processed 1587 items.
別の方法は、一時ファイルを使用することです。
find . -print -fprintf tmp.file .
wc -c <tmp.file # using the file as argument instead causes the file name to be printed after the count
echo "Processed `wc -c <tmp.file` items." # sh variant
echo "Processed $(wc -c <tmp.file) items." # bash variant
すべての-print
検索コマンドは、カウントにまったく影響しません。