Czy jest coś szybszego niż „find. | wc -l` zliczać pliki w katalogu?

8

Nierzadko muszę liczyć liczbę plików w katalogu, czasem dochodzi do milionów.

Czy istnieje lepszy sposób niż ich liczenie i liczenie find . | wc -l? Czy istnieje jakieś wywołanie systemu plików, które można wykonać na ext3 / 4, które jest mniej intensywne we / wy?

MattPark
źródło
3
Liczysz nie tylko pliki, ale także katalogi. Jeśli chcesz tylko liczyć pliki, użyj „znajdź. -Type f | wc -l”, jeśli chcesz policzyć dowiązania symboliczne i zwykłe pliki, użyj „znajdź. -Type f -or -type l | wc -l”
FSMaxB
Katalog jest rodzajem pliku, podobnie jak urządzenia, dowiązania symboliczne i gniazda. Zwykłe pliki to podzbiór plików.
Toby Speight,
1
Podany przykład sugeruje, że chcesz rekurencyjnego liczenia - jeśli nie, to potrzebujesz find -maxdepth 1. Zauważ, że przy obecnym podejściu policzysz dwukrotnie dowolną nazwę zawierającą znak nowej linii.
Toby Speight,

Odpowiedzi:

13

Nie podstawowe przyspieszenie, ale przynajmniej coś :)

find . -printf \\n | wc -l

Naprawdę nie musisz przekazywać listy nazw plików, wystarczy tylko nowy wiersz. Ten wariant jest o około 15% szybszy na moim Ubuntu 12.04.3, gdy katalogi są buforowane w pamięci RAM. Ponadto ten wariant będzie działał poprawnie z nazwami plików zawierającymi znaki nowej linii.

Co ciekawe, ten wariant wydaje się nieco wolniejszy niż powyższy:

find . -printf x | wc -c

Specjalny przypadek - ale naprawdę szybki

Jeśli katalog znajduje się we własnym systemie plików, możesz po prostu policzyć i-węzły:

df -i .

Jeśli liczba katalogów i plików w innych katalogach niż liczona nie zmienia się bardzo, możesz po prostu odjąć tę znaną liczbę od bieżącego df -iwyniku. W ten sposób będziesz mógł bardzo szybko policzyć pliki i katalogi.

pabouk
źródło
„Ten wariant jest o około 15% szybszy ...” zastanawiam się, czy istnieje jakiś przydatny trik, którego używasz do pomiaru czasu?
Brian Z
4
@BrianZ: Możesz określić czas polecenia, poprzedzając je czasem. time find /usr/src/ -printf \\n | wc -l, możesz wyczyścić sudo sync && sudo sysctl -w vm.drop_caches=3
skrzynki
Widziałem więc stały wzrost prędkości o 2% przy każdej z pierwszych 2 opcji bez buforowania. Więc tak, to całkiem fajny sposób na zrobienie tego. Liczenie i-węzłów jest zdecydowanie najlepsze, jeśli środowisko jest skonfigurowane do tego. Nie zastanawiałem się nad tym.
MattPark,
Czy -printf xma być taki sam jak -printf '\0'? Nie widzę tego w dokumentach.
CMCDragonkai
@CMCDragonkai: Działanie -printfdziała podobnie do printf()funkcji w C z tą różnicą, że %dyrektywy mają inne znaczenie. Akcja jest wywoływana dla każdego znalezionego pliku. Oznacza to, że -printf xwypisze znak xdla każdego znalezionego pliku (wypróbuj!) I -printf '\0'wypisze znak NULL (kod ASCII 0) dla każdego znalezionego pliku. -printf '\0'nie ma specjalnego znaczenia. Oba będą działać tak samo w przykładzie z wc -ctą odpowiedzią.
pabouk
3

Napisałem ffcnt właśnie w tym celu. Pobiera fizyczne przesunięcie samych katalogów za pomocą fiemapioctl, a następnie planuje przejście katalogu w wielu sekwencyjnych przejściach w celu ograniczenia losowego dostępu. To, czy rzeczywiście uzyskasz przyspieszenie, find | wc zależy od kilku czynników:

  • typ systemu plików: fiemapnajbardziej skorzystają systemy plików takie jak ext4, które obsługują ioctl
  • prędkość losowego dostępu: dyski twarde korzystają znacznie więcej niż dyski SSD
  • układ katalogu: im większa liczba zagnieżdżonych katalogów, tym większy potencjał optymalizacji

(ponowne) montowanie z, relatimea nawet nodiratimemoże również poprawić prędkość (dla wszystkich metod), gdy dostęp w przeciwnym razie spowodowałby aktualizację metadanych.

the8472
źródło
To ostatnie zdanie jest cenną wskazówką! Myślę, że link do twojego programu zostałby ulepszony, gdybyś dodał podsumowanie jego działania. Preferujemy odpowiedzi, które same w sobie są kompletne, na wypadek, gdyby coś złego stało się z połączonym zasobem (ale oczywiście zachowaj link).
Toby Speight
2

Właściwie to w moim systemie (Arch Linux) to polecenie

   ls -A | wc -l

jest szybszy niż wszystkie powyższe:

   $ time find . | wc -l
  1893

   real    0m0.027s
   user    0m0.004s
   sys     0m0.004s
   $ time find . -printf \\n  | wc -l
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time find . -printf x  | wc -c
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time ls -A | wc -l
   1892

   real    0m0.007s
   user    0m0.000s
   sys     0m0.004s
MariusMatutiae
źródło
Myślę, że problem z ls polega na tym, że często zwraca coś takiego, /bin/ls: Argument list too longjeśli używasz globowania, ale znowu może działać rekurencyjnie, podobnie jak find, więc może to jest coś do rozważenia, nie używaj find, jeśli nie jest potrzebny.
MattPark,
Wydaje się, że jest tak późno (wiele lat), aby komentować na ten temat, ale ls -Awymień tylko pliki w bieżącym katalogu, a findbez -maxdepth 1argumentów przeszuka rekursywnie wszystkie podkatalogi.
Luciano,