Как лучше всего подсчитывать «найденные» результаты?

101

Мое текущее решение было бы таким find <expr> -exec printf '.' \; | wc -c, но это занимает слишком много времени, когда есть более 10000 результатов. Нет ли более быстрого / лучшего способа сделать это?

МечМК1
источник
используйте wc -l в результатах поиска
Мануэль Сельва

Ответы:

86

Попробуйте вместо этого (требуется find«s -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линия)

Жиль Кено
источник
6
Не эквивалентно, так надежнее =)
Жиль Кено
6
Это не более надежно, если флаг -printf для поиска не поддерживается на вашей платформе. ;-)
Randy Howard
7
Обратите внимание, что вы можете сэкономить еще несколько наносекунд, не цитируя точку в-printf '.'
Йенс
6
@Jens - особенно если принять во внимание время , чтобы напечатать что
Brian Agnew
6
При таком небольшом тесте на тайминги, вероятно, влияют другие факторы, а не то, что вы хотите измерить. Полезнее будет поэкспериментировать с большим деревом. Но это дает мой голос за то, что я действительно сделал то, о чем просил ОП.
tripleee
134

Почему нет

find <expr> | wc -l

как простое портативное решение? Ваше исходное решение порождает новый процесс printf для каждого отдельного найденного файла, и это очень дорого (как вы только что обнаружили).

Обратите внимание, что это будет слишком большим, если у вас есть имена файлов со встроенными символами новой строки, но если они у вас есть, я подозреваю, что ваши проблемы немного глубже.

Брайан Агнью
источник
9
-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
while read -r -d ''; do
    ((n++)) # count
    # maybe perform another act on file
done < <(find <expr> -print0)
echo $n

Это всего лишь модификация решения, найденного в BashGuide, которое должным образом обрабатывает файлы с нестандартными именами, делая findвыходной ограничитель нулевым байтом print0и считывая его с использованием ''(нулевой байт) в качестве разделителя цикла.

Джон Б.
источник
4

Это моя countfilesфункция в моем ~/.bashrc(она достаточно быстрая, должна работать для Linux и FreeBSD find, и ее не обманывают пути к файлам, содержащие символы новой строки; последний wcпросто считает байты NUL):

countfiles () 
{ 
   command find "${1:-.}" -type f -name "${2:-*}" -print0 | 
       command tr -dc '\0' | command wc -c;
return 0
}

countfiles

countfiles ~ '*.txt'
Карло
источник