Jaki jest najlepszy sposób zliczania wyników „znajdź”?

101

Moje obecne rozwiązanie byłoby takie find <expr> -exec printf '.' \; | wc -c, ale trwa to zbyt długo, gdy wyników jest ponad 10000. Czy nie ma szybszego / lepszego sposobu na zrobienie tego?

MechMK1
źródło
użyj wc -l na swoich wynikach wyszukiwania
Manuel Selva

Odpowiedzi:

86

Spróbuj tego zamiast (wymaga find„s -printfwsparcia):

find <expr> -type f -printf '.' | wc -c

Będzie to bardziej niezawodne i szybsze niż liczenie linii.

Zwróć uwagę, że używam polecenia find, a printfnie polecenia zewnętrznego.


Ławmy trochę:

$ ls -1
a
e
l
ll.sh
r
t
y
z

Test porównawczy mojego fragmentu:

$ time find -type f -printf '.' | wc -c
8

real    0m0.004s
user    0m0.000s
sys     0m0.007s

Z pełnymi liniami:

$ time find -type f | wc -l
8

real    0m0.006s
user    0m0.003s
sys     0m0.000s

Więc moje rozwiązanie jest szybsze =) (ważną częścią jest reallinia)

Gilles Quenot
źródło
6
Nie równoważne, jest bardziej niezawodne =)
Gilles Quenot
6
Nie jest bardziej niezawodne, jeśli flaga -printf do znalezienia nie jest obsługiwana na Twojej platformie. ;-)
Randy Howard
7
Zauważ, że możesz zaoszczędzić kilka nanosekund więcej, nie cytując kropki w-printf '.'
Jens
6
@Jens - zwłaszcza jeśli weźmiesz pod uwagę czas potrzebny na wpisanie tego
Brian Agnew
6
Przy tak małym benchmarku czasy są prawdopodobnie zdominowane przez inne czynniki niż to, co chcesz zmierzyć. Bardziej przydatny byłby eksperyment z dużym drzewem. Ale to daje mój głos za robieniem tego, o co prosił OP.
tripleee
134

Dlaczego nie

find <expr> | wc -l

jako proste rozwiązanie przenośne? Twoje oryginalne rozwiązanie tworzy nowy proces printf dla każdego znalezionego pliku i jest to bardzo kosztowne (jak właśnie znalazłeś).

Zauważ, że liczba ta przekroczy, jeśli masz nazwy plików z osadzonymi znakami nowego wiersza, ale jeśli je masz, to podejrzewam, że Twoje problemy są nieco głębsze.

Brian Agnew
źródło
9
-1: zepsuje plik z nowymi
liniami
21
Nie sądzę, żeby to uzasadniało głosowanie przeciw, biorąc pod uwagę, że ograniczenie nazwy pliku / nowej linii jest dość rzadkie i odnotowane powyżej. Wolniej? Być może. Biorąc pod uwagę, że odpytujesz system plików, podejrzewam, że różnica w szybkości jest niewielka. W moich 10000 plikach mierzę różnicę 3 ms
Brian Agnew,
8
Różnica w wydajności między poleceniami „find <expr> | wc -l” i „find <expr> -printf. | wc -c 'są bardzo małe. Buforowanie (tj. Jeśli uruchomisz to samo znalezisko dwa razy w tym samym drzewie) jest znacznie ważniejsze. IMHO rozwiązanie z "wc -l" jest dużo bardziej intuicyjne.
pitseeker
5

To rozwiązanie jest z pewnością wolniejsze niż niektóre inne find -> wcrozwiązania tutaj, ale jeśli byłeś skłonny zrobić coś innego z nazwami plików oprócz ich zliczania, możesz readz findwyniku.

n=0
while read -r -d ''; do
    ((n++)) # count
    # maybe perform another act on file
done < <(find <expr> -print0)
echo $n

Jest to po prostu modyfikacja rozwiązania znalezionego w BashGuide, które poprawnie obsługuje pliki o niestandardowych nazwach, ustawiając findseparator wyjściowy bajtem NUL, używając print0i odczytując z niego ''(bajt NUL) jako ogranicznik pętli.

John B.
źródło
4

To jest moja countfilesfunkcja w moim ~/.bashrc(jest dość szybka, powinna działać dla Linuksa i FreeBSD findi nie daje się zwieść ścieżkom plików zawierających znaki nowej linii; ostatnia wcliczy tylko NUL bajtów):

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

countfiles

countfiles ~ '*.txt'
Carlo
źródło