Как лучше всего подсчитывать «найденные» результаты?
101
Мое текущее решение было бы таким find <expr> -exec printf '.' \; | wc -c, но это занимает слишком много времени, когда есть более 10000 результатов. Нет ли более быстрого / лучшего способа сделать это?
Это не более надежно, если флаг -printf для поиска не поддерживается на вашей платформе. ;-)
Randy Howard
7
Обратите внимание, что вы можете сэкономить еще несколько наносекунд, не цитируя точку в-printf '.'
Йенс
6
@Jens - особенно если принять во внимание время , чтобы напечатать что
Brian Agnew
6
При таком небольшом тесте на тайминги, вероятно, влияют другие факторы, а не то, что вы хотите измерить. Полезнее будет поэкспериментировать с большим деревом. Но это дает мой голос за то, что я действительно сделал то, о чем просил ОП.
tripleee
134
Почему нет
find <expr> | wc -l
как простое портативное решение? Ваше исходное решение порождает новый процессprintf для каждого отдельного найденного файла, и это очень дорого (как вы только что обнаружили).
Обратите внимание, что это будет слишком большим, если у вас есть имена файлов со встроенными символами новой строки, но если они у вас есть, я подозреваю, что ваши проблемы немного глубже.
-1: будет разрыв файла с новой строкой, и это медленнее, чем подсчет байтов =)
Жиль Куэно
23
Я не думаю, что это гарантирует отрицательное голосование, учитывая, что ограничение имени файла / новой строки довольно редко и отмечено выше. Помедленнее ? Возможно. Учитывая, что вы запрашиваете файловую систему, я подозреваю, что разница в скорости небольшая. В моих 10 000 файлов я измеряю разницу в 3 мс
Брайан Агнью
8
Разница в производительности между find <expr> | wc -l и find <expr> -printf. | wc -c 'очень малы. Кэширование (то есть, если вы дважды запускаете один и тот же поиск по одному и тому же дереву) гораздо важнее. ИМХО решение с "wc -l" намного более интуитивно понятно.
pitseeker
5
Это решение, безусловно, медленнее, чем некоторые другие find -> wcрешения здесь, но если вы были склонны сделать что-то еще с именами файлов в дополнение к их подсчету, вы могли бы сделать это readиз findвывода.
n=0
whileread -r -d ''; do
((n++)) # count# maybe perform another act on filedone < <(find <expr> -print0)
echo$n
Это всего лишь модификация решения, найденного в BashGuide, которое должным образом обрабатывает файлы с нестандартными именами, делая findвыходной ограничитель нулевым байтом print0и считывая его с использованием ''(нулевой байт) в качестве разделителя цикла.
Это моя countfilesфункция в моем ~/.bashrc(она достаточно быстрая, должна работать для Linux и FreeBSD find, и ее не обманывают пути к файлам, содержащие символы новой строки; последний wcпросто считает байты NUL):
Ответы:
Попробуйте вместо этого (требуется
find
«s-printf
поддержка):find <expr> -type f -printf '.' | wc -c
Это будет надежнее и быстрее, чем подсчет строк.
Обратите внимание, что я использую
find
'sprintf
, а не внешнюю команду.Давайте немного жмемся:
Тест моего фрагмента:
$ 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
линия)источник
-printf '.'
Почему нет
как простое портативное решение? Ваше исходное решение порождает новый процесс
printf
для каждого отдельного найденного файла, и это очень дорого (как вы только что обнаружили).Обратите внимание, что это будет слишком большим, если у вас есть имена файлов со встроенными символами новой строки, но если они у вас есть, я подозреваю, что ваши проблемы немного глубже.
источник
Это решение, безусловно, медленнее, чем некоторые другие
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
Это всего лишь модификация решения, найденного в 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'
источник