Jaki jest najlepszy sposób na policzenie liczby plików w katalogu?

11

Jeśli parsowanie danych wyjściowych lsjest niebezpieczne, ponieważ może uszkodzić niektóre funky (spacje \n, ...), jaki jest najlepszy sposób, aby poznać liczbę plików w katalogu?

Zwykle polegam na findunikaniu tego analizowania, ale podobnie find mydir | wc -lzepsuje się z tych samych powodów.

Obecnie pracuję nad systemem Solaris, ale szukam odpowiedzi tak przenośnej dla różnych jednorożców i różnych powłok.

rahmu
źródło
3
Nie jestem pewien, czy to duplikat, czy coś mi brakuje?
rahmu
1
Może to być duplikat, ale nie wskazanego pytania. finddostanie ci rekursywnie liczbę plików (użyj, -maxdepth 1jeśli tego nie chcesz. find mydir -maxdepth 1 -type f -printf \\n | wc -lpowinien obsługiwać znaki specjalne w nazwie pliku, ponieważ nigdy nie są drukowane w pierwszej kolejności
Anthon

Odpowiedzi:

16

Co powiesz na tę sztuczkę?

find . -maxdepth 1 -exec echo \; | wc -l

Tak przenośny jak findi wc.

rozcietrzewiacz
źródło
5
To nie działa (wyświetla n+1pliki w moim systemie Debian). Nie filtruje również zwykłych plików.
Chris Down
4
Dałem tylko ogólny przykład. Działa, ale to, jak działa, zależy od sposobu dostosowania findpolecenia do konkretnych potrzeb. Tak, ten zawiera wszystkie katalogi, w tym .(co może być powodem, dla którego widzisz wynik jako n+1).
rozcietrzewiacz
Lubię tę sztuczkę, bardzo sprytną; ale jestem zaskoczony, że nie ma prostego, prostego sposobu, aby to zrobić!
rahmu
3
@ChrisDown OP nie określa filtrowania zwykłych plików, prosi o liczbę plików w katalogu. Aby pozbyć się problemu n + 1, użyj find . -maxdepth 1 ! -name . -exec echo \; | wc -l; niektóre starsze wersje findnie mają -not.
Arcege
3
Zauważ, że -maxdepthnie jest to standard (rozszerzenie GNU jest teraz obsługiwane również przez kilka innych implementacji).
Stéphane Chazelas
11

Z bash, bez zewnętrznych narzędzi i pętli:

shopt -s dotglob
files=(*)
echo ${#files[@]}

W ksh zamień shopt -s dotglobna FIGNORE=.?(.). W Zsh zastąp go setopt glob_dotslub usuń shoptpołączenie i użyj files=(*(D)). (Lub po prostu upuść linię, jeśli nie chcesz dołączać plików kropek.) Przenośnie, jeśli nie obchodzi Cię pliki kropek:

set -- *
echo $#

Jeśli chcesz dołączyć pliki kropek:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c
enzotib
źródło
2
Pierwszy przykład drukuje 1dla pustego katalogu, gdy nullglobnie jest włączony. W zsh, a=(*(DN));echo ${#a}z N( nullglob) kwalifikator nie powoduje błędu do pustego katalogu.
nisetama
8
find . ! -name . -prune -print | grep -c /

Powinien być dość przenośny na systemy po latach 80.

Dotyczy to wszystkich pozycji katalogu oprócz .i ..w bieżącym katalogu.

Aby policzyć pliki również w podkatalogach:

find .//. ! -name . | grep -c //

(ten powinien być przenośny nawet na Unix V6 (1975), ponieważ nie potrzebuje -prune)

Stéphane Chazelas
źródło
Jedna z rzadkich przenośnych odpowiedzi na tej stronie, jeśli nie jedyna.
xhienne
Wczoraj głosowałem tę odpowiedź, ponieważ okazało się, że działa ona również dobrze w przypadku katalogów innych niż bieżący katalog ( find dirname ! -name dirname -prune -print). I od tego czasu zastanawiałem się, czy jest jakiś szczególny powód, aby używać grep -c /zamiast wc -l(co jest prawdopodobnie bardziej powszechnie stosowane do liczenia).
Anthony Geoghegan
1
find dirname ! -name dirnamenie działa, jeśli istnieją inne katalogi, które są nazwane dirname. Lepiej jest użyć find dirname/. ! -name .. wc -lzlicza liczbę wierszy, nazwy plików mogą składać się z kilku wierszy, ponieważ znak nowej linii jest tak samo ważny jak dowolny w nazwie pliku.
Stéphane Chazelas
6

Próbować:

ls -b1A | wc -l

-bBędą miały znaki niedrukowalne, -Apokaże wszystkie pliki z wyjątkiem .i ..jeden na linię (domyślnie na rurze, ale dobre być jawne).

Tak długo, jak uwzględniamy języki skryptowe wyższego poziomu, tutaj jest jeden wiersz w Pythonie:

python -c 'import os; print len(os.listdir(os.sep))'

Lub z pełnym „znajdź”:

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'
Arcege
źródło
1

Yoc może korzystać z takiej konstrukcji:

I=0; for i in * ; do ((I++)); done ; echo $I

Ale obawiam się, że możesz zlikwidować błąd, tak Argument list too long.jakbyś miał zbyt wiele plików w katalogu. Jednak przetestowałem go na katalogu z 10 miliardami plików i działał dobrze.

wysypka
źródło
3
Nie będzie to również działać w przypadku ukrytych plików, chyba że powłoka jest skonfigurowana do rozszerzania tych plików *.
Lekensteyn,
gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley,
4
@ Rush: to polecenie nigdy nie powinno zwiększać „listy argumentów zbyt długo”. Dzieje się tak tylko z zewnętrznym poleceniem (więc nigdy z for.
enzotib
1

Czy zastanawiałeś się nad perlem, który powinien być względnie przenośny?

Coś jak:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";
cjc
źródło
0

Spróbuj tego => Używanie ls z -i (dla numeru węzła) i -F (dołącza nazwę katalogu z opcjami „/”).

ls -ilF | egrep -v '/' | wc -l
Saumil
źródło
0

Z perljednowarstwowym (sformatowanym dla czytelności):

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

lub

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

Możesz używać perlfunkcji modyfikujących tablice, takich jak greplub mapw drugiej wersji. Zobacz perldoc -f readdirprzykład użycia grep.

cas
źródło
0

Najprostsza wersja, z której korzystam cały czas i z którą nigdy nie miałem problemów to: ls -b1 | wc -l

Piotr
źródło
Możesz napotkać problemy, jeśli nazwa pliku zawiera \nznaki funky lub inne (tak, niektóre unikaty na to pozwalają).
rahmu
1
Próbowałem tego wyraźnie przed opublikowaniem odpowiedzi i nie miałem z tym żadnych problemów. Użyłem menedżera plików nautilus, aby zmienić nazwę pliku zawierającego \ n, aby spróbować.
Peter,
Masz rację, to tak nie działa. Nie wiem, co zrobiłem, kiedy to przetestowałem. Próbowałem ponownie i zaktualizowałem moją odpowiedź.
Peter,
Nie, polecenie jest OK, ale istnieje już podobne rozwiązanie i ukryte pliki nie są liczone.
xhienne,
0

Oprócz opartej na findodpowiedzi odpowiedzi zaproponowanej przez Stéphane , oto odpowiedź zgodna z POSIX na podstawie ls:

ls -qf | tail -n +3 | wc -l
Xhienne
źródło