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?
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 procesprintf 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.
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
whileread -r -d ''; do
((n++)) # count# maybe perform another act on filedone < <(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.
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):
Odpowiedzi:
Spróbuj tego zamiast (wymaga
find
„s-printf
wsparcia):find <expr> -type f -printf '.' | wc -c
Będzie to bardziej niezawodne i szybsze niż liczenie linii.
Zwróć uwagę, że używam polecenia
find
, aprintf
nie polecenia zewnętrznego.Ławmy trochę:
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
real
linia)źródło
-printf '.'
Dlaczego nie
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.
źródło
To rozwiązanie jest z pewnością wolniejsze niż niektóre inne
find -> wc
rozwiązania tutaj, ale jeśli byłeś skłonny zrobić coś innego z nazwami plików oprócz ich zliczania, możeszread
zfind
wyniku.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
find
separator wyjściowy bajtem NUL, używającprint0
i odczytując z niego''
(bajt NUL) jako ogranicznik pętli.źródło
To jest moja
countfiles
funkcja w moim~/.bashrc
(jest dość szybka, powinna działać dla Linuksa i FreeBSDfind
i nie daje się zwieść ścieżkom plików zawierających znaki nowej linii; ostatniawc
liczy 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'
źródło