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?


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.


„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.


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

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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.