Jak mogę liczyć pliki z określonym rozszerzeniem i katalogi, w których się znajdują?

14

Chcę wiedzieć, ile zwykłych plików ma rozszerzenie .cw dużej złożonej strukturze katalogów, a także w ilu katalogach te pliki są rozmieszczone. Dane wyjściowe, których chcę, to tylko te dwie liczby.

Widziałem to pytanie, jak uzyskać liczbę plików, ale muszę też znać liczbę katalogów, w których znajdują się pliki.

  • Moje nazwy plików (w tym katalogi) mogą zawierać dowolne znaki; mogą zaczynać się od .lub -i mieć spacje lub znaki nowej linii.
  • Mogę mieć pewne dowiązania symboliczne, których nazwy kończą się .c, i dowiązania symboliczne do katalogów. Nie chcę, aby dowiązania symboliczne były śledzone lub liczone, a przynajmniej chcę wiedzieć, czy i kiedy są one liczone.
  • Struktura katalogów ma wiele poziomów, a katalog najwyższego poziomu (katalog roboczy) zawiera co najmniej jeden .cplik.

Pośpiesznie napisałem kilka poleceń w powłoce (Bash), aby je policzyć, ale nie sądzę, aby wynik był dokładny ...

shopt -s dotglob
shopt -s globstar
mkdir out
for d in **/; do
     find "$d" -maxdepth 1 -type f -name "*.c" >> out/$(basename "$d")
done
ls -1Aq out | wc -l
cat out/* | wc -l

Powoduje to wysyłanie skarg na niejednoznaczne przekierowania, pomijanie plików w bieżącym katalogu i wyzwalanie znaków specjalnych (na przykład przekierowane findwyjście drukuje nowe wiersze w nazwach plików ) i zapisuje całą masę pustych plików (ups).

Jak w sposób niezawodny wyliczyć moje .cpliki i zawierające je katalogi?


Jeśli to pomaga, oto kilka poleceń, aby utworzyć strukturę testową ze złymi nazwami i dowiązaniami symbolicznymi:

mkdir -p cfiles/{1..3}/{a..b} && cd cfiles
mkdir space\ d
touch -- i.c -.c bad\ .c 'terrible
.c' not-c .hidden.c
for d in space\ d 1 2 2/{a..b} 3/b; do cp -t "$d" -- *.c; done
ln -s 2 dirlink
ln -s 3/b/i.c filelink.c

W powstałej strukturze 7 katalogów zawiera .cpliki, a 29 zwykłych plików kończy się na .c(jeśli dotglobjest wyłączone, gdy polecenia są uruchamiane) (jeśli się przeliczyłem, daj mi znać). To są liczby, których chcę.

Prosimy nie korzystać z tego konkretnego testu.

NB: Odpowiedzi w dowolnej powłoce lub innym języku będą przeze mnie testowane i doceniane. Jeśli będę musiał zainstalować nowe pakiety, nie ma problemu. Jeśli znasz rozwiązanie GUI, zachęcam do udostępnienia (ale nie mogę posunąć się tak daleko, aby zainstalować cały DE, aby go przetestować) :) Używam Ubuntu MATE 17.10.

Zanna
źródło
Napisanie programu radzenia sobie ze złymi nawykami programistycznymi okazało się dość trudne;)
WinEunuuchs2Unix

Odpowiedzi:

16

Nie badałem danych wyjściowych za pomocą dowiązań symbolicznych, ale:

find . -type f -iname '*.c' -printf '%h\0' |
  sort -z |
  uniq -zc |
  sed -zr 's/([0-9]) .*/\1 1/' |
  tr '\0' '\n' |
  awk '{f += $1; d += $2} END {print f, d}'
  • findPolecenie wypisuje nazwy katalogów każdego .cpliku znajdzie.
  • sort | uniq -cda nam liczbę plików w każdym katalogu ( sortmoże to być niepotrzebne tutaj, nie jestem pewien)
  • z sed, zamieniam nazwę katalogu na 1, eliminując w ten sposób wszystkie możliwe dziwne znaki, tylko liczbę i 1pozostałe
  • umożliwiając mi konwersję do wyniku oddzielonego znakiem nowej linii za pomocą tr
  • które następnie sumuję z awk, aby uzyskać całkowitą liczbę plików i liczbę katalogów, które zawierały te pliki. Pamiętaj, że dtutaj jest to w zasadzie to samo co NR. Mógłbym pominąć wstawiając 1w sedpoleceniu, a tylko drukowane NRtutaj, ale myślę, że to jest nieco jaśniejsze.

Do czasu trdane są rozdzielane przez NUL, zabezpieczone przed wszystkimi prawidłowymi nazwami plików.


Za pomocą Zsh i Bash można printf %quzyskać ciąg cytowany, który nie zawierałby w nim nowych linii. Możesz być w stanie zrobić coś takiego:

shopt -s globstar dotglob nocaseglob
printf "%q\n" **/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'

Jednakże, chociaż **nie powinno się rozszerzać dla dowiązań symbolicznych do katalogów , nie mogłem uzyskać pożądanego wyjścia na bash 4.4.18 (1) (Ubuntu 16.04).

$ shopt -s globstar dotglob nocaseglob
$ printf "%q\n" ./**/*.c | awk -F/ '{NF--; f++} !c[$0]++{d++} END {print f, d}'
34 15
$ echo $BASH_VERSION
4.4.18(1)-release

Ale zsh działało dobrze, a komendę można uprościć:

$ printf "%q\n" ./**/*.c(D.:h) | awk '!c[$0]++ {d++} END {print NR, d}'
29 7

DUmożliwia to glob, aby wybrać dot plików, .wybiera zwykłe pliki (tak, nie symlinks) oraz :hwydruki tylko ścieżkę do katalogu, a nie nazwa pliku (jak find„s %h) (patrz rozdziały poświęcone Filename Generation i modyfikatorów ). Tak więc za pomocą polecenia awk musimy tylko policzyć liczbę unikalnych katalogów, a liczba wierszy to liczba plików.

muru
źródło
To cudownie. Wykorzystuje dokładnie to, czego potrzebujesz i nie więcej. Dziękujemy za nauczenie :)
Zanna,
@Zanna, jeśli opublikujesz jakieś polecenia, aby odtworzyć strukturę katalogów z dowiązaniami symbolicznymi oraz oczekiwane dane wyjściowe z dowiązaniami symbolicznymi, być może uda mi się to odpowiednio naprawić.
muru,
Dodałem kilka poleceń, aby stworzyć (niepotrzebnie skomplikowaną jak zwykle) strukturę testową z dowiązaniami symbolicznymi.
Zanna,
@Zanna Myślę, że to polecenie nie wymaga żadnych zmian, aby uzyskać 29 7. Jeśli dodam -Ldo find, to idzie w górę 41 10. Jakiej mocy potrzebujesz?
muru,
1
Dodano metodę zsh + awk. Prawdopodobnie jest jakiś sposób, aby sam zsh wydrukował dla mnie liczbę, ale nie mam pojęcia, jak to zrobić.
mur
11

Python ma os.walk, dzięki czemu takie zadania są łatwe, intuicyjne i automatycznie niezawodne nawet w obliczu dziwnych nazw plików, takich jak te, które zawierają znaki nowej linii. Ten skrypt Python 3, które pierwotnie opublikowany na czacie , jest przeznaczony do uruchomienia w bieżącym katalogu (ale to nie musi znajdować się w bieżącym katalogu, można zmienić to, co ścieżka przechodzi do os.walk):

#!/usr/bin/env python3

import os

dc = fc = 0
for _, _, fs in os.walk('.'):
    c = sum(f.endswith('.c') for f in fs)
    if c:
        dc += 1
        fc += c
print(dc, fc)

Wyświetla liczbę katalogów, które bezpośrednio zawierają co najmniej jeden plik, którego nazwa kończy się na .c, następnie spację, a następnie liczbę plików, których nazwy kończą się na .c. Pliki „ukryte” - to znaczy pliki, których nazwy zaczynają się od .- są włączone, a katalogi ukryte są obsługiwane podobnie.

os.walkrekurencyjnie przechodzi przez hierarchię katalogów. Wymienia on wszystkie katalogi, które są rekurencyjnie dostępny od punktu początkowego ją podać, uzyskując informacje na temat każdego z nich jako krotki trzech wartości root, dirs, files. Dla każdego katalogu, do którego przechodzi, (w tym pierwszego, któremu nadasz nazwę):

  • rootzawiera nazwę ścieżki tego katalogu. Należy pamiętać, że jest to całkowicie niezwiązane z „katalogu” systemu /(a także niezwiązane /root), chociaż to by iść do tych, jeśli zaczniesz tam. W takim przypadku rootzaczyna się od ścieżki .- bieżący katalog - i idzie wszędzie pod nim.
  • dirszawiera listę ścieżek wszystkich podkatalogów katalogu, w którym obecnie znajduje się nazwa root.
  • fileszawiera listę ścieżek wszystkich plików znajdujących się w katalogu, w którym obecnie znajduje się nazwa, rootale które same nie są katalogami. Zauważ, że obejmuje to inne rodzaje plików niż zwykłe pliki, w tym dowiązania symboliczne, ale wygląda na to, że nie spodziewasz się, że takie wpisy się kończą .ci jesteś zainteresowany ich zobaczeniem.

W takim przypadku muszę tylko zbadać trzeci element krotki files(który wywołuję fsw skrypcie). Podobnie jak findpolecenie, Python os.walkprzechodzi dla mnie do podkatalogów; jedyne, co muszę sprawdzić, to nazwy plików, które każdy z nich zawiera. findJednak w przeciwieństwie do polecenia, os.walkautomatycznie wyświetla mi listę tych nazw plików.

Ten skrypt nie korzysta z dowiązań symbolicznych. Prawdopodobnie nie chcesz, aby dowiązania symboliczne były śledzone dla takiej operacji, ponieważ mogą one tworzyć cykle, a nawet jeśli nie ma cykli, te same pliki i katalogi mogą być przeglądane i liczone wiele razy, jeśli są dostępne poprzez różne dowiązania symboliczne.

Jeśli kiedykolwiek chciałeś os.walkpodążać za dowiązaniami symbolicznymi - czego zwykle byś nie robił - możesz followlinks=trueto zrobić. Oznacza to, że zamiast pisać os.walk('.')można pisać os.walk('.', followlinks=true). Powtarzam, że rzadko byś tego chciał, szczególnie w przypadku zadania takiego jak to, w którym rekurencyjnie wyliczasz całą strukturę katalogów, bez względu na to, jak duża jest, i zliczasz wszystkie pliki, które spełniają pewne wymagania.

Eliah Kagan
źródło
7

Znajdź + Perl:

$ find . -type f -iname '*.c' -printf '%h\0' | 
    perl -0 -ne '$k{$_}++; }{ print scalar keys %k, " $.\n" '
7 29

Wyjaśnienie

findKomenda znajdzie jakieś zwykłe pliki (więc nie ma dowiązania lub katalogi), a następnie wydrukować nazwę katalogu są w ( %h), a następnie \0.

  • perl -0 -ne: czytaj wiersz po wierszu ( -n) i zastosuj skrypt podany przez -edo każdego wiersza. -0Ustawia separator linii wejściowej do \0tak możemy przeczytać wejście null ograniczony.
  • $k{$_}++: $_jest specjalną zmienną, która przyjmuje wartość bieżącego wiersza. Jest to używane jako klucz do skrótu %k , którego wartości to liczba wyświetleń każdej linii wejściowej (nazwy katalogu).
  • }{: jest to skrótowy sposób pisania END{}. Wszelkie polecenia po nim }{zostaną wykonane raz, po przetworzeniu wszystkich danych wejściowych.
  • print scalar keys %k, " $.\n": keys %kzwraca tablicę kluczy w haszu %k. scalar keys %kpodaje liczbę elementów w tej tablicy, liczbę widocznych katalogów. Jest on drukowany wraz z bieżącą wartością $.specjalnej zmiennej, która przechowuje bieżący numer linii wejściowej. Ponieważ jest to uruchamiane na końcu, bieżącym numerem linii wejściowej będzie numer ostatniej linii, a więc liczba linii widocznych do tej pory.

Możesz rozwinąć polecenie perl do tego, dla przejrzystości:

find  . -type f -iname '*.c' -printf '%h\0' | 
    perl -0 -e 'while($line = <STDIN>){
                    $dirs{$line}++; 
                    $tot++;
                } 
                $count = scalar keys %dirs; 
                print "$count $tot\n" '
terdon
źródło
4

Oto moja sugestia:

#!/bin/bash
tempfile=$(mktemp)
find -type f -name "*.c" -prune >$tempfile
grep -c / $tempfile
sed 's_[^/]*$__' $tempfile | sort -u | grep -c /

Ten krótki skrypt tworzy plik tymczasowy, znajduje każdy plik w bieżącym katalogu i kończy się na nim .ci zapisuje listę do pliku tymczasowego. grepjest następnie używany do zliczania plików (następujące: Jak uzyskać liczbę plików w katalogu przy użyciu wiersza polecenia? ) dwa razy: Po raz drugi katalogi, które są wymienione wiele razy, są usuwane za pomocą sort -upo usunięciu nazw plików z każdego wiersza za pomocą sed.

Działa to również poprawnie z nowymi grep -c /liniami w nazwach plików: zlicza tylko linie z ukośnikiem i dlatego uwzględnia tylko pierwszy wiersz nazwy pliku z wieloma liniami na liście.

Wynik

$ tree
.
├── 1
   ├── 1
      ├── test2.c
      └── test.c
   └── 2
       └── test.c
└── 2
    ├── 1
       └── test.c
    └── 2

$ tempfile=$(mktemp);find -type f -name "*.c" -prune >$tempfile;grep -c / $tempfile;sed 's_[^/]*$__' $tempfile | sort -u | grep -c /
4
3
deser
źródło
4

Mały shellscript

Proponuję mały skrypt powłoki bash z dwoma głównymi wierszami poleceń (i zmienną, filetypeaby ułatwić przełączanie w celu wyszukiwania innych typów plików).

Nie szuka ani w dowiązaniach symbolicznych, tylko zwykłe pliki.

#!/bin/bash

filetype=c
#filetype=pdf

# count the 'filetype' files

find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l | tr '\n' ' '

# count directories containing 'filetype' files

find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l

Pełny skrypt powłoki

Jest to bardziej szczegółowa wersja, która uwzględnia również dowiązania symboliczne,

#!/bin/bash

filetype=c
#filetype=pdf

# counting the 'filetype' files

echo -n "number of $filetype files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l

echo -n "number of $filetype symbolic links in the current directory tree: "
find -type l -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype normal files in the current directory tree: "
find -type f -name "*.$filetype" -ls|sed 's#.* \./##'|wc -l
echo -n "number of $filetype symbolic links in the current directory tree including linked directories: "
find -L -type f -name "*.$filetype" -ls 2> /tmp/c-counter |sed 's#.* \./##' | wc -l; cat /tmp/c-counter; rm /tmp/c-counter

# list directories with and without 'filetype' files (good for manual checking; comment away after test)
echo '---------- list directories:'
 find    -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
#find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;

# count directories containing 'filetype' files

echo -n "number of directories with $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \;|grep 'contains file(s)$'|wc -l

# list and count directories including symbolic links, containing 'filetype' files
echo '---------- list all directories including symbolic links:'
find -L -type d -exec bash -c "ls -AF '{}' |grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)' || echo '{} empty'" \;
echo ''
echo -n "number of directories (including symbolic links) with $filetype files: "
find -L -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null && echo '{} contains file(s)'" \; 2>/dev/null |grep 'contains file(s)$'|wc -l

# count directories without 'filetype' files (good for checking; comment away after test)

echo -n "number of directories without $filetype files: "
find -type d -exec bash -c "ls -AF '{}'|grep -e '\.'${filetype}$ -e '\.'${filetype}'\*'$ > /dev/null || echo '{} empty'" \;|grep 'empty$'|wc -l

Wyjście testowe

Z krótkiego skryptu:

$ ./ccntr 
29 7

Z pełnego shellscript:

$ LANG=C ./c-counter
number of c files in the current directory tree: 29
number of c symbolic links in the current directory tree: 1
number of c normal files in the current directory tree: 29
number of c symbolic links in the current directory tree including linked directories: 42
find: './cfiles/2/2': Too many levels of symbolic links
find: './cfiles/dirlink/2': Too many levels of symbolic links
---------- list directories:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)

number of directories with c files: 7
---------- list all directories including symbolic links:
. empty
./cfiles contains file(s)
./cfiles/2 contains file(s)
find: './cfiles/2/2': Too many levels of symbolic links
./cfiles/2/b contains file(s)
./cfiles/2/a contains file(s)
./cfiles/3 empty
./cfiles/3/b contains file(s)
./cfiles/3/a empty
./cfiles/dirlink empty
find: './cfiles/dirlink/2': Too many levels of symbolic links
./cfiles/dirlink/b contains file(s)
./cfiles/dirlink/a contains file(s)
./cfiles/1 contains file(s)
./cfiles/1/b empty
./cfiles/1/a empty
./cfiles/space d contains file(s)

number of directories (including symbolic links) with c files: 9
number of directories without c files: 5
$ 
sudodus
źródło
4

Prosta wkładka Perl One:

perl -MFile::Find=find -le'find(sub{/\.c\z/ and -f and $c{$File::Find::dir}=++$c}, @ARGV); print 0 + keys %c, " $c"' dir1 dir2

Lub prościej za pomocą findpolecenia:

find dir1 dir2 -type f -name '*.c' -printf '%h\0' | perl -l -0ne'$c{$_}=1}{print 0 + keys %c, " $."'

Jeśli lubisz grać w golfa i masz najnowszego (mniej niż dekadę) Perla:

perl -MFile::Find=find -E'find(sub{/\.c$/&&-f&&($c{$File::Find::dir}=++$c)},".");say 0+keys%c," $c"'
find -type f -name '*.c' -printf '%h\0'|perl -0nE'$c{$_}=1}{say 0+keys%c," $."'
Hynek-Pichi- Vychodil
źródło
2

Rozważ użycie locatepolecenia, które jest znacznie szybsze niż findpolecenie.

Uruchamianie na danych testowych

$ sudo updatedb # necessary if files in focus were added `cron` daily.
$ printf "Number Files: " && locate -0r "$PWD.*\.c$" | xargs -0 -I{} sh -c 'test ! -L "$1" && echo "regular file"' _  {} | wc -l &&  printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -cu | wc -l
Number Files: 29
Number Dirs.: 7

Dzięki Muru za odpowiedź, która pomogła mi przez usunięcie symbolicznych linków z pliku Unixa i Linuksa .

Podziękowania dla Terdona za odpowiedź $PWD(nie skierowaną na mnie) w odpowiedzi na Unix i Linux .


Oryginalna odpowiedź poniżej, do której odnoszą się komentarze

Skrócona forma:

$ cd /
$ sudo updatedb
$ printf "Number Files: " && locate -cr "$PWD.*\.c$"
Number Files: 3523
$ printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l 
Number Dirs.: 648
  • sudo updatedbZaktualizuj bazę danych używaną przez locatepolecenie, jeśli .cpliki zostały utworzone dzisiaj lub jeśli pliki zostały usunięte .cdzisiaj.
  • locate -cr "$PWD.*\.c$"zlokalizuj wszystkie .cpliki w bieżącym katalogu i jego dzieci ( $PWD). Zamiast wypisywać nazwy plików i drukować liczbę z -cargumentem. W rOkreśla regex zamiast domyślnego *pattern*dopasowania, które mogą przynieść zbyt wiele wyników.
  • locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l. Znajdź wszystkie *.cpliki w bieżącym katalogu i poniżej. Usuń nazwę pliku, sedpozostawiając tylko nazwę katalogu. Policz liczbę plików w każdym katalogu za pomocą uniq -c. Policz liczbę katalogów za pomocąwc -l .

Zacznij od bieżącego katalogu z jedną linią

$ cd /usr/src
$ printf "Number Files: " && locate -cr "$PWD.*\.c$" &&  printf "Number Dirs.: " && locate -r "$PWD.*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l
Number Files: 3430
Number Dirs.: 624

Zauważ, jak zmieniła się liczba plików i liczba katalogów. Wierzę, że wszyscy użytkownicy mają/usr/src katalog i mogą uruchamiać powyższe polecenia z różną liczbą, w zależności od liczby zainstalowanych jąder.

Długa forma:

Długa forma obejmuje czas, dzięki czemu można zobaczyć, ile czasu locateminęło find. Nawet jeśli musisz uruchomić sudo updatedb, jest wiele razy szybszy niż jeden find /.

───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ sudo time updatedb
0.58user 1.32system 0:03.94elapsed 48%CPU (0avgtext+0avgdata 7568maxresident)k
48inputs+131920outputs (1major+3562minor)pagefaults 0swaps
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Files: " && locate -cr $PWD".*\.c$")
Number Files: 3523

real    0m0.775s
user    0m0.766s
sys     0m0.012s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate -r $PWD".*\.c$" | sed 's%/[^/]*$%/%' | uniq -c | wc -l) 
Number Dirs.: 648

real    0m0.778s
user    0m0.788s
sys     0m0.027s
───────────────────────────────────────────────────────────────────────────────────────────

Uwaga: To są wszystkie pliki na WSZYSTKICH dyskach i partycjach. tzn. możemy również wyszukiwać polecenia systemu Windows:

$ time (printf "Number Files: " && locate *.exe -c)
Number Files: 6541

real    0m0.946s
user    0m0.761s
sys     0m0.060s
───────────────────────────────────────────────────────────────────────────────────────────
rick@alien:~/Downloads$ time (printf "Number Dirs.: " && locate *.exe | sed 's%/[^/]*$%/%' | uniq -c | wc -l) 
Number Dirs.: 3394

real    0m0.942s
user    0m0.803s
sys     0m0.092s

Mam automatycznie zamontowane trzy partycje NTFS systemu Windows 10 /etc/fstab . Pamiętaj, że lokalizacje wiedzą wszystko!

Ciekawa liczba:

$ time (printf "Number Files: " && locate / -c &&  printf "Number Dirs.: " && locate / | sed 's%/[^/]*$%/%' | uniq -c | wc -l)
Number Files: 1637135
Number Dirs.: 286705

real    0m15.460s
user    0m13.471s
sys     0m2.786s

Zliczenie 1 637 135 plików w 286 705 katalogach zajmuje 15 sekund. YMMV.

Aby locatezapoznać się ze szczegółowym podziałem obsługi wyrażeń regularnych poleceń (wydaje się, że nie jest to konieczne w tym pytaniu i odpowiedzi, ale jest używane na wszelki wypadek), przeczytaj to: Używać opcji „zlokalizuj” w określonym katalogu?

Dodatkowe czytanie z ostatnich artykułów:

WinEunuuchs2Unix
źródło
1
To nie liczy plików w określonym katalogu. Jak zauważyłeś, zlicza wszystkie pasujące pliki (lub katalogi lub dowolny inny typ pliku) .c(zwróć uwagę, że pęknie, jeśli -.cw bieżącym katalogu jest plik o nazwie, ponieważ nie cytujesz *.c), a następnie wydrukuje wszystkie katalogi w systemie, niezależnie od tego, czy zawierają pliki .c.
terdon
@terdon Możesz przekazać katalog ~/my_c_progs/*.c. Liczy 638 katalogów z .cprogramami, całkowite katalogi są pokazane później jako 286,705. Poprawię odpowiedź na podwójny cytat „” .c ”. Dzięki za wskazówkę.
WinEunuuchs2Unix
3
Tak, możesz użyć czegoś takiego locate -r "/path/to/dir/.*\.c$", ale nigdzie nie wspomniano w odpowiedzi. Podajesz tylko link do innej odpowiedzi, która o tym wspomina, ale bez wyjaśnienia, jak dostosować ją do odpowiedzi na zadane pytanie. Cała twoja odpowiedź skupia się na tym, jak policzyć całkowitą liczbę plików i katalogów w systemie, co nie ma znaczenia dla zadanego pytania, które brzmiało: „jak mogę policzyć liczbę plików .c i liczbę katalogów zawierających. c pliki w określonym katalogu ". Również twoje liczby są błędne, spróbuj na przykładzie w PO.
terdon
@terdon Dzięki za wkład. Poprawiłem odpowiedź za pomocą twoich sugestii i odpowiedzi, którą zamieściłeś na innej stronie SE dla $PWDzmiennej: unix.stackexchange.com/a/188191/200094
WinEunuuchs2Unix
1
Teraz musisz upewnić się, że $PWDnie zawiera znaków, które mogą być wyjątkowe w wyrażeniu regularnym
muru