Czy istnieje polecenie bash, które zlicza pliki pasujące do wzorca?
Na przykład chcę uzyskać liczbę wszystkich plików w katalogu, które pasują do tego wzorca: log*
Ten prosty jednolinijkowy powinien działać w każdej powłoce, nie tylko w bashu:
ls -1q log* | wc -l
ls -1q da ci jedną linię na plik, nawet jeśli zawierają spacje lub znaki specjalne, takie jak nowe linie.
Dane wyjściowe są przesyłane potokiem do wc -l, które zlicza liczbę wierszy.
-l
, ponieważ wymaga tostat(2)
na każdym pliku i na potrzeby liczenia nic nie dodaje.ls
, ponieważ tworzy proces potomny.log*
jest rozszerzany przez powłokę, a niels
, więc wystarczyłoby prosteecho
.logs
w tym katalogu, zawartość tego katalogu dzienników również zostanie policzona. To prawdopodobnie nie jest zamierzone.Możesz to zrobić bezpiecznie (tj. Nie będziesz mieć problemów z plikami ze spacjami lub
\n
w ich nazwie) za pomocą basha:Musisz włączyć
nullglob
, aby nie uzyskać literału*.log
w$logfiles
tablicy, jeśli żaden plik nie pasuje. (Zobacz Jak „cofnąć” polecenie „set -x” ?, aby zapoznać się z przykładami bezpiecznego resetowania).źródło
shopt -u nullglob
powinien zostać pominięty, jeślinullglob
nie był ustawiony, gdy zacząłeś.*.log
po prostu*
spowoduje policzenie katalogów. Jeśli pliki, które chcesz wyliczyć, mają tradycyjną konwencję nazewnictwaname.extension
, użyj*.*
.Wiele odpowiedzi tutaj, ale niektóre nie biorą pod uwagę
-l
)*.log
zamiastlog*
logs
który pasujelog*
)Oto rozwiązanie, które obsługuje je wszystkie:
Wyjaśnienie:
-U
powoduje,ls
że wpisy nie są sortowane, co oznacza, że nie musi ładować całej listy katalogów do pamięci-b
wypisuje znaki specjalne w stylu C dla znaków niegraficznych, powodując, że znaki nowej linii są drukowane jako\n
.-a
drukuje wszystkie pliki, nawet pliki ukryte (niepotrzebne, gdy globlog*
nie sugeruje żadnych ukrytych plików)-d
wypisuje katalogi bez próby wypisania zawartości katalogu, cols
normalnie by zrobił-1
upewnia się, że jest w jednej kolumnie (ls robi to automatycznie podczas pisania do potoku, więc nie jest to bezwzględnie konieczne)2>/dev/null
przekierowuje stderr, więc jeśli jest 0 plików dziennika, zignoruj komunikat o błędzie. (Zauważ,shopt -s nullglob
że spowodowałoby tols
to wyświetlenie zamiast tego całego katalogu roboczego).wc -l
zużywa listę katalogów podczas generowania, więc dane wyjściowels
nigdy nie są w pamięci w żadnym momencie.--
Nazwy plików są oddzielone od polecenia za pomocą,--
aby nie były rozumiane jako argumenty dols
(w przypadkulog*
usunięcia)Powłoka będzie rozszerzyć
log*
do pełnej listy plików, które mogą wyczerpać pamięć, jeśli jest dużo plików, więc następnie uruchomienie go przez grep ma być lepiej:Ten ostatni obsługuje bardzo duże katalogi plików bez zajmowania dużej ilości pamięci (chociaż używa podpowłoki). Nie
-d
jest już potrzebny, ponieważ wyświetla tylko zawartość bieżącego katalogu.źródło
W przypadku wyszukiwania rekurencyjnego:
wc -c
policzy liczbę znaków na wyjściufind
, a-printf x
mówi,find
że wypisuje po jednymx
dla każdego wyniku.W przypadku wyszukiwania nierekurencyjnego wykonaj następujące czynności:
źródło
-name '*.log'
policzy wszystkie pliki, czego potrzebowałem w moim przypadku użycia. Również flaga -maxdepth jest niezwykle przydatna, dzięki!find
; po prostu wypisz coś innego niż dosłowna nazwa pliku.Przyjęta odpowiedź na to pytanie jest nieprawidłowa, ale mam niską reprezentację, więc nie mogę dodać do niej komentarza.
Prawidłowej odpowiedzi na to pytanie udziela Mat:
Problem z akceptowaną odpowiedzią polega na tym, że wc -l zlicza liczbę znaków nowej linii i liczy je, nawet jeśli wypisują na terminal jako „?” na wyjściu 'ls -l'. Oznacza to, że zaakceptowana odpowiedź NIE powiedzie się, gdy nazwa pliku zawiera znak nowej linii. Przetestowałem sugerowane polecenie:
i błędnie zgłasza wartość 2, nawet jeśli istnieje tylko 1 plik pasujący do wzorca, którego nazwa zawiera znak nowej linii. Na przykład:
źródło
Jeśli masz dużo plików i nie chcesz używać eleganckiego
shopt -s nullglob
rozwiązania tablicowego i bash, możesz użyć funkcji find i tak dalej, o ile nie drukujesz nazwy pliku (która może zawierać znaki nowej linii).Spowoduje to znalezienie wszystkich plików, które pasują do dziennika * i które nie zaczynają się od
.*
- „Nie nazwa. *” Jest zbędne, ale ważne jest, aby pamiętać, że domyślnym ustawieniem „ls” jest nie pokazywanie plików z kropkami, ale domyślne ponieważ find to ich uwzględnienie.To jest prawidłowa odpowiedź i obsługuje dowolne nazwy plików, które możesz do niego rzucić, ponieważ nazwa pliku nigdy nie jest przekazywana między poleceniami.
Ale
shopt nullglob
odpowiedź jest najlepszą odpowiedzią!źródło
find
vs używaniels
to dwa różne sposoby rozwiązania problemu.find
nie zawsze jest obecny na maszynie, alels
zwykle jest,find
prawdopodobnie nie ma wszystkich tych wymyślnych opcjils
.-maxdepth 1
find
robi to domyślnie. Może to spowodować zamieszanie, jeśli ktoś nie zdaje sobie sprawy, że istnieje ukryty folder podrzędny, i może sprawić, że korzystanie z niego będzie korzystnels
w niektórych okolicznościach, które domyślnie nie zgłaszają ukrytych plików.Oto moja jedyna wkładka do tego.
źródło
set --
nie robi nic poza przygotowaniem nas do$#
tego, że przechowuje liczbę argumentów wiersza poleceń, które zostały przekazane do programu powłokiMożesz użyć opcji -R, aby znaleźć pliki wraz z plikami wewnątrz katalogów rekurencyjnych
możesz użyć wzorów na grep
źródło
Ważna uwaga
(niewystarczająca reputacja do komentowania)
To jest BUGGY :
Jeśli
shopt -s nullglob
zdarzy się, że zostanie ustawiony, wypisuje liczbę WSZYSTKICH zwykłych plików, a nie tylko tych ze wzorcem (testowane na CentOS-8 i Cygwin). Kto wie, jakie inne bezsensowne błędyls
mają?To jest PRAWIDŁOWE i znacznie szybsze:
Wykonuje oczekiwaną pracę.
A czasy pracy są różne.
Pierwszy:
0.006
na CentOS i0.083
na Cygwin (na wypadek, gdyby był używany ostrożnie).Drugi:
0.000
na CentOS i0.003
na Cygwin.źródło
Możesz łatwo zdefiniować takie polecenie, używając funkcji powłoki. Ta metoda nie wymaga żadnego zewnętrznego programu i nie generuje żadnego procesu potomnego. Nie próbuje niebezpiecznego
ls
parsowania i dobrze radzi sobie ze znakami „specjalnymi” (spacje, znaki nowej linii, ukośniki odwrotne itd.). Opiera się tylko na mechanizmie rozszerzania nazw plików udostępnianym przez powłokę. Jest kompatybilny przynajmniej z sh, bash i zsh.Poniższy wiersz definiuje funkcję o nazwie
count
która wypisuje liczbę argumentów, z którymi została wywołana.Po prostu nazwij to pożądanym wzorem:
Aby wynik był poprawny, gdy wzorzec globowania nie pasuje, opcja powłoki
nullglob
(lubfailglob
- co jest domyślnym zachowaniem w zsh) musi być ustawiona w momencie rozwinięcia. Można to ustawić w następujący sposób:W zależności od tego, co chcesz policzyć, możesz być również zainteresowany opcją powłoki
dotglob
.Niestety, przynajmniej w przypadku basha nie jest łatwo ustawić te opcje lokalnie. Jeśli nie chcesz ustawiać ich globalnie, najprostszym rozwiązaniem jest użycie funkcji w bardziej zawiły sposób:
Jeśli chcesz odzyskać lekką składnię
count log*
lub naprawdę chcesz uniknąć tworzenia podpowłoki, możesz zhakować coś w następujący sposób:Jako bonus, ta funkcja ma bardziej ogólne zastosowanie. Na przykład:
Przekształcając funkcję w plik skryptu (lub równoważny program w C), wywoływany z PATH, można ją również komponować z programami takimi jak
find
ixargs
:źródło
Dużo się zastanawiałem nad tą odpowiedzią, zwłaszcza biorąc pod uwagę rzeczy, które nie są analizowane . Na początku próbowałem
co działało, gdyby istniała tylko nazwa pliku, taka jak
ale nie udało się, jeśli utworzyłem taką nazwę pliku
W końcu wymyśliłem to, co poniżej. Uwaga: Próbowałem uzyskać liczbę wszystkich plików w katalogu (bez żadnych podkatalogów). Myślę, że wraz z odpowiedziami @Mat i @Dan_Yard, a także mając co najmniej większość wymagań stawianych przez @mogsie (nie jestem pewien co do pamięci). Myślę, że odpowiedź @mogsie jest poprawna, ale zawsze staram się trzymać z daleka od analizowania,
ls
chyba że jest to wyjątkowo specyficzna sytuacja.Bardziej czytelnie:
Robi to wyszukiwanie specjalnie dla plików, ograniczając wyjście znakiem null (aby uniknąć problemów ze spacjami i wysunięciami), a następnie zliczając liczbę znaków null. Liczba plików będzie o jeden mniejsza niż liczba znaków null, ponieważ na końcu będzie znak pusty.
Aby odpowiedzieć na pytanie PO, należy rozważyć dwa przypadki
1) Wyszukiwanie nierekurencyjne:
2) Wyszukiwanie rekurencyjne. Zwróć uwagę, że to, co znajduje się w
-name
parametrze, może wymagać zmiany w celu uzyskania nieco innego zachowania (ukryte pliki itp.).Jeśli ktoś chciałby skomentować porównanie tych odpowiedzi z tymi, o których wspomniałem w tej odpowiedzi, zrób to.
Uwaga, dotarłem do tego procesu myślowego, otrzymując tę odpowiedź .
źródło
Oto, co zawsze robię:
źródło
awk 'END{print NR}'
powinien być równoważny zwc -l
.Oznacza to wyświetlenie jednego pliku w wierszu, a następnie przekazanie go do polecenia zliczania słów z przełączaniem parametrów na liczbę wierszy.
źródło
Aby policzyć wszystko, po prostu potokiem ls do linii liczącej słowa:
Aby liczyć ze wzorem, najpierw potokuj do grep:
źródło