Jak korzystać z wc i potoków, aby dowiedzieć się, ile plików i katalogów znajduje się w określonym katalogu?

10

Jak mogę użyć licznika słów ( wc) i potoków, aby policzyć, ile plików lub katalogów znajduje się w /usr/binkatalogu?

gotówkowy
źródło
Ta praca domowa? Możesz poprosić o pomoc, po prostu określ ją jako taką, jeśli tak jest.
slm
tak, ale piszę tutaj, aby dowiedzieć się, jak coś osiągnąć, ponieważ jestem nowy w Linuksie i może to być bardzo skomplikowane. I już rozwiązałem powyższe pytanie za pomocą tego polecenia
gotówka
ls / bin / usr / bin | sortuj | uniq | wc -
gotówka
np. Proszenie o pomoc jest w porządku! Po prostu oznacz to etykietą, aby ludzie wiedzieli, że wszyscy tutaj chętnie pomagają ludziom, którzy próbują nauczyć się drobniejszych aspektów Uniksa.
slm

Odpowiedzi:

13

Jednym z podejść byłoby skorzystanie z, lsaby dać nam listę plików, ale chcemy, aby ta lista wyświetlała tylko 1 plik lub katalog w wierszu. -1Przełącznik zrobi to za nas.

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

Przykład

Utwórz powyższe przykładowe dane w pustym katalogu.

$ mkdir dir{1..3}
$ touch file{A..C}

Sprawdź to:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

Teraz do zliczenia można użyć wc -ldo zliczenia liczby wierszy odpowiadających plikowi lub katalogowi w danych ls -1wyjściowych.

$ ls -1 | wc -l
6

(zauważ jednak, że nie zawiera ukrytych plików)

Liczenie plików lub katalogów, po prostu nie razem

Aby policzyć pliki lub katalogi, musisz nieco zmienić taktykę. W tym przypadku skorzystałbym, ls -lponieważ pokazuje, co to jest katalog, a co plik.

Przykład

$ ls -l
total 12
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Następnie możemy użyć grepdo odfiltrowania katalogów lub katalogów innych niż katalogi:

# directories
$ ls -l | grep "^d"
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir1
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir2
drwxrwxr-x 2 saml saml 4096 Nov 16 09:48 dir3

# regular files
$ ls -l | grep "^-"
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileA
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileB
-rw-rw-r-- 1 saml saml    0 Nov 16 09:49 fileC

Teraz użyj wc -lponownie, aby policzyć powyższe:

# directories
$ ls -l | grep "^d" | wc -l
3

# regular files
$ ls -l | grep "^-" | wc -l
3

Chociaż można uniknąć wccałkowicie, a stosowanie grepjest -copcja:

$ ls -l | grep -c '^d'

(znowu, ukryte pliki nie są uwzględnione. Pamiętaj, że katalogi i zwykłe są dwoma typami plików. Istnieje wiele innych, takich jak nazwane potoki, dowiązania symboliczne, urządzenia, gniazda ...).

Rekurencja

Jeśli potrzebujesz rekursywnie znaleźć pliki i katalogi /usr/bin, prawdopodobnie zechcesz całkowicie zmienić taktykę i skorzystać z innego narzędzia o nazwie find.

Przykład

$ find /usr/bin | wc -l
4632

(chociaż powyżej /usr/binsiebie jest wliczone w liczenie)

Tych samych technik, których użyłem powyżej, można użyć lsdo zrobienia czegoś podobnego, ale lsogólnie nie jest to dobre narzędzie do analizy wyników. findz drugiej strony został stworzony do tego i oferuje przełączniki do wyszukiwania plików lub katalogów.

# find files
$ find /usr/bin -type f

# find directories
$ find /usr/bin -type d

(zauważ, że tym razem findzawiera ukryte pliki (oprócz .i ..)).

nowe linie?

Nigdy nie dowiedziałem się, dlaczego znak nowej linii jest znakiem legalnym, którego można używać podczas tworzenia nazw plików lub nazw katalogów. Tak więc metody omówione powyżej wykorzystują wci lsnie byłyby z nimi sprzeczne, więc używaj ich z myślą o tym.

Przykład

Utwórz katalog i nazwę pliku z nowymi liniami.

$ mkdir $'dir4\n5'
$ touch $'fileD\nE'

ls pokazuje je poprawnie:

$ ls -1
dir1
dir2
dir3
dir4?5
fileA
fileB
fileC
fileD?E

Ale wcliczy katalogi i pliki zawierające znaki nowej linii jako 2 elementy, a nie jeden.

$ ls -1 | wc -l
10

Jedną z metod obejścia tego problemu , jeśli używa się implementacji GNU, findjest wykorzystanie findmożliwości wydrukowania czegoś innego w miejsce każdego znalezionego pliku, a następnie policzenie go zamiast tego.

Przykład

$ find . -printf . | wc -c
9

Tutaj jesteśmy odkrycie wszystko w bieżącym katalogu (z wyjątkiem ..), a drukuje kropki ( .) dla każdego, a następnie liczenie kropek za pomocą wc„s zdolność count bajtów zamiast linii wc -c.

Bibliografia

slm
źródło
Chociaż wszystkie pliki /usr/binbędą dobrze sformatowane (i nie będą zawierały spacji, więc technicznie możesz nawet po prostu echo * | wc -w), warto zauważyć, że wszystkie zepsują się na nazwach plików zawierających nowe linie.
evilsoup
@evilsoup - nie, nie wierzę ls -llub ls -1złamie b / c liczymy linie, a nie słowa! findMoże pęknąć, ale znowu liczymy linie nie słowa.
slm
Chodzi mi o to, że spowoduje to (myślę, że jestem teraz w systemie Windows, więc nie mogę przetestować), jeśli pliki zawierają nowe linie . Tak więc touch $'foo\nbar'w pustym katalogu, po którym następuje jedno z twoich poleceń (powiedzmy ls -1 | wc -l) zgłasza dwa pliki, a nie jeden - ponieważ ten plik ma dwie linie wc. Chyba że lszastąpi nowy wiersz inną postacią (nie sądzę, że tak, ale znowu nie jestem teraz w stanie przetestować).
evilsoup
@evilsoup - poprawne, znak nowej linii. jest legalnym char. dla nazw plików, a metody nie byłyby w stanie poprawnie konkurować z tymi typami nazw plików.
slm
@StephaneChazelas - czy wc -cjest problem z liczeniem okresów?
slm
5

Jeśli chcesz uzyskać podział liczby każdego typu plików rekurencyjnie w jakimś katalogu, z GNU find, możesz zrobić:

find /some/dir/. ! -name . -printf '%y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

W /usr/binmoim systemie daje to:

   3727 regular files
    710 symbolic links

On /dev:

     83 block devices
    203 character devices
     31 directories
    426 symbolic links
      1 FIFOs
      1 Unix domain sockets

W przypadku dowiązań symbolicznych, jeśli wolisz je policzyć jako typ pliku, na który wskazują symbolic links, możesz zmienić to na:

find /some/dir/. ! -name . -printf '%Y\n' | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/N/broken symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Co teraz daje moje /usr/bin:

      1 directories
   4434 regular files
      2 broken symbolic links

(zepsute dowiązanie symboliczne to dowiązanie symboliczne do pliku, dla którego findnie można określić typu, ponieważ plik nie istnieje lub znajduje się w katalogu, do którego nie masz dostępu, lub istnieje pętla w rozdzielczości ścieżki do pliku W moim przypadku te 2, w których dowiązania symboliczne do plików, które już zniknęły).

Żaden z nich się nie liczy .i ... Jeśli chcesz je uwzględnić (dlaczego?), Nie ma innego wyjścia findniż założenie, że są one dostępne dla każdego katalogu i licz je systematycznie:

find /some/dir/. -printf '%y\n' \( -name . -printf 'd\n' -o \
  -type d -printf 'd\nd\n' \)  | sort | uniq -c | sed '
  s/f/regular files/;t
  s/d/directories/;t
  s/l/symbolic links/;t
  s/s/Unix domain sockets/;t
  s/b/block devices/;t
  s/c/character devices/;t
  s/p/FIFOs/;t
  s/D/Doors/;t
  s/n/network special files/;t
  s/.$/others (&)/'

Co następnie daje moje /usr/bin:

      2 directories
   3727 regular files
    710 symbolic links

Jeśli nie masz dostępu do GNU find, możesz przepisać pierwszy jako:

find /some/dir/. ! -name . \( \
  -type f -exec printf '%.0sregular files\n' {} + -o \
  -type d -exec printf '%.0sdirectories\n' {} + -o \
  -type l -exec printf '%.0ssymbolic links\n' {} + -o \
  -type s -exec printf '%.0sUnix domain sockets\n' {} + -o \
  -type b -exec printf '%.0sblock devices\n' {} + -o \
  -type c -exec printf '%.0scharacter devices\n' {} + -o \
  -type p -exec printf '%.0sFIFOs\n' {} + -o \
  -exec printf '%.0sothers\n' {} + \) | sort | uniq -c

Mówiąc ściśle, nie liczymy plików, ale wpisy katalogu . Jak /usr/binzwykle katalog zawiera kilka pozycji wskazujących na ten sam plik. Na przykład tutaj mam:

$ ls -lid /usr/bin/{nvi,nview,nex}
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nex
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nvi
672252 -rwxr-xr-x 3 root root 434616 May 25 07:40 /usr/bin/nview

Są to 3 wpisy katalogu (inaczej nazwy plików lub twarde łącza) do tego samego pliku (ten z i-węzłem 672252. Aby policzyć pliki zamiast pozycji katalogu i GNU findi GNU uniq(ignorowanie .i ..pliki, które i tak są twardymi linkami do innych katalogów):

find /some/dir/. ! -name . -printf '%y\t%D:%i\n' |
  sort -u |
  cut -f1 |
  uniq -c |
  sed '
    s/f/regular files/;t
    s/d/directories/;t
    s/l/symbolic links/;t
    s/s/Unix domain sockets/;t
    s/b/block devices/;t
    s/c/character devices/;t
    s/p/FIFOs/;t
    s/d/Doors/;t
    s/n/network special files/;t
    s/.$/others (&)/'

W moim /usr/binprzypadku daje to:

   3711 regular files
    710 symbolic links
Stéphane Chazelas
źródło
0

Nie powiedziałeś, czy chcesz rekursywnie cały plik w / usr / bin, czy tylko poniżej pierwszego poziomu. Poza tym, jak zdobędziesz wyliczane słowa? Zwykłym sposobem na sprawdzenie tego jest uruchomienie find w wc. W ten sposób: znajdź / usr / bin | wc -l Znajdź wyświetli wszystko, katalogi i pliki. Wc -l policzy wszystkie linie w wynikach wyszukiwania. Czy to zadanie klasowe? W porządku, jeśli tak, ale zastanawiałem się, dlaczego potrzebowałeś tych informacji, aby móc dokładniej dostosować odpowiedź. Daj mi znać, jeśli potrzebujesz więcej. Costa

cdr
źródło
0

W skrócie, bez zewnętrznych narzędzi.

cd dir/ || exit; shopt -s nullglob; shopt -s dotglob; count=(*); echo "${#count}"

W skrócie, bez zewnętrznych narzędzi i rekurencji.

shopt -s globstar; shopt -s dotglob 
for dir in **/*/; do 
  unset d f
  for files in "$dir"*; do 
    [[ -f $files ]] && ((++f))
    [[ -d $files ]] && ((++d))
  done; 
  printf '%s\n' "$dir -  files: ${f:-0} - directories: ${d:-0}"
done
llua
źródło
Zauważ, że drugi podążałby za dowiązaniami symbolicznymi podczas rekurencji (i liczył dowiązania do zwykłych plików jako zwykłe pliki oraz dowiązania symboliczne do katalogów jako katalogów), nie liczyłby plików i katalogów w bieżącym katalogu i nie liczył .ani ..wpisów. Możesz rozróżnić plik od zwykłego pliku.
Stéphane Chazelas