Wie verwende ich wc und piping, um herauszufinden, wie viele Dateien und Verzeichnisse sich in einem bestimmten Verzeichnis befinden?


10

Wie kann ich mit word counter ( wc) und Piping zählen, wie viele Dateien oder Verzeichnisse sich im /usr/binVerzeichnis befinden?


Diese Hausaufgaben? Es ist in Ordnung, um Hilfe zu bitten. Identifizieren Sie sie einfach als solche, falls dies der Fall ist.
slm

Ja, aber ich poste hier, um eine Vorstellung davon zu bekommen, wie man etwas erreicht, da ich neu in Linux bin und es sehr kompliziert sein kann. Und ich löse die Frage oben bereits mit diesem Befehl
Bargeld

ls / bin / usr / bin | sortieren | uniq | wc -
Bargeld

np. Es ist vollkommen in Ordnung, um Hilfe zu bitten! Beschriften Sie es einfach, damit die Leute wissen, dass jeder hier normalerweise gerne Menschen hilft, die versuchen, die Feinheiten von Unix zu lernen.
slm

Antworten:


13

Ein Ansatz wäre ls, uns eine Liste der Dateien zu geben, aber wir möchten, dass diese Liste garantiert nur 1 Datei oder Verzeichnis pro Zeile anzeigt. Der -1Schalter erledigt dies für uns.

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

Beispiel

Erstellen Sie die obigen Beispieldaten in einem leeren Verzeichnis.

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

Prüfen Sie:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

Zum Zählen können Sie jetzt wc -ldie Anzahl der Zeilen zählen, die einer Datei oder einem Verzeichnis in der ls -1Ausgabe entsprechen.

$ ls -1 | wc -l
6

(Beachten Sie jedoch, dass die versteckten Dateien nicht enthalten sind.)

Dateien oder Verzeichnisse zählen, nur nicht zusammen

Um entweder Dateien oder Verzeichnisse zu zählen, müssen Sie Ihre Taktik leicht ändern. In diesem Fall würde ich verwenden, ls -lda es zeigt, was ein Verzeichnis und was eine Datei ist.

Beispiel

$ 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

Dann können wir grepVerzeichnisse oder Nicht-Verzeichnisse wie folgt herausfiltern:

# 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

Verwenden Sie jetzt einfach noch wc -leinmal, um Folgendes zu zählen:

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

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

Obwohl, können Sie vermeiden , wcüberhaupt, und die Verwendung grep‚s -cOption:

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

(Auch hier sind versteckte Dateien nicht enthalten. Beachten Sie, dass Verzeichnisse und reguläre Dateien zwei Arten von Dateien sind. Es gibt viele weitere wie Named Pipes, symbolische Links, Geräte, Sockets ...).

Rekursion

Wenn Sie die Dateien und Verzeichnisse rekursiv unter finden müssen, /usr/binmöchten Sie wahrscheinlich die Taktik vollständig ändern und ein anderes Tool namens verwenden find.

Beispiel

$ find /usr/bin | wc -l
4632

(obwohl über sich /usr/binselbst in der Zählung enthalten ist)

Die gleichen Techniken, die ich oben verwendet habe, könnten verwendet werden ls, um etwas Ähnliches zu tun, sind jedoch lsim Allgemeinen kein gutes Werkzeug zum Parsen der Ausgabe. findAuf der anderen Seite wurde dafür gebaut und bietet Schalter, um entweder Dateien oder Verzeichnisse zu finden.

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

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

(Beachten Sie, dass diesmal findversteckte Dateien enthalten sind (außer .und ..)).

Newlines?

Ich habe nie herausgefunden, warum ein Zeilenumbruchzeichen ein zulässiges Zeichen beim Erstellen von Dateinamen oder Verzeichnisnamen ist. Die oben diskutierten Methoden verwenden diese wcund lswürden nicht mit diesen konkurrieren. Verwenden Sie sie daher in diesem Sinne.

Beispiel

Erstellen Sie ein Verzeichnis und einen Dateinamen mit Zeilenumbrüchen.

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

ls zeigt sie richtig:

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

Aber wczählt die Verzeichnisse und Dateien , die Zeilenumbrüche als 2 Elemente enthalten, nicht ein.

$ ls -1 | wc -l
10

Eine Methode, um dies zu umgehen, wenn Sie die GNU-Implementierung von verwenden, findbesteht darin, die findFähigkeit zu nutzen , anstelle jeder gefundenen Datei etwas anderes zu drucken und diese stattdessen zu zählen.

Beispiel

$ find . -printf . | wc -c
9

Hier finden wir alles im aktuellen Verzeichnis (außer ..) und drucken jeweils einen Punkt ( .) und zählen dann die Punkte, indem wir die wcFähigkeit verwenden, Bytes anstelle von Zeilen zu zählen wc -c.

Verweise


Während /usr/binalle Dateien in gut formatiert sein werden (und auch keine Leerzeichen enthalten, so dass Sie dies technisch gesehen auch nur tun können echo * | wc -w), ist es erwähnenswert, dass all diese Dateien bei Dateinamen mit Zeilenumbrüchen beschädigt werden.
Evilsoup

@evilsoup - nein ich glaube nicht das ls -loder ls -1wird b / c brechen wir zählen Zeilen, keine Wörter! Das findmag brechen, aber wir zählen wieder Zeilen, keine Wörter.
slm

Was ich damit meine ist, dass dies (ich denke, ich bin gerade unter Windows, also kann ich nicht testen) kaputt geht, wenn die Dateien Zeilenumbrüche enthalten . In touch $'foo\nbar'einem leeren Verzeichnis, gefolgt von einem Ihrer Befehle (z. B. ls -1 | wc -l), werden zwei statt einer Datei gemeldet, da diese eine Datei aus zwei Zeilen wcbesteht. Es sei denn, er lsersetzt Zeilenumbrüche durch einen anderen Charakter (ich glaube nicht, aber ich bin momentan nicht in der Lage zu testen).
Evilsoup

@evilsoup - richtig, newline char. ist ein gesetzlicher Charakter. für Dateinamen, und die Methoden könnten nicht korrekt mit diesen Dateinamen umgehen.
slm

@StephaneChazelas - ist wc -cein Problem beim Zählen der Perioden?
slm

5

Wenn Sie mit GNU eine rekursive Aufschlüsselung der Anzahl der einzelnen Dateitypen unter einem bestimmten Verzeichnis erhalten möchten find, haben Sie folgende Möglichkeiten:

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 (&)/'

Auf /usr/binmeinem System gibt das:

   3727 regular files
    710 symbolic links

Am /dev:

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

Wenn Sie Symlinks lieber als den Typ der Datei zählen möchten, auf die sie verweisen symbolic links, können Sie sie ändern in:

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 (&)/'

Was jetzt für meine gibt /usr/bin:

      1 directories
   4434 regular files
      2 broken symbolic links

(Ein fehlerhafter Symlink ist ein Symlink zu einer Datei, für die findder Typ nicht bestimmt werden kann, weil die Datei nicht vorhanden ist oder sich in einem Verzeichnis befindet, auf das Sie keinen Zugriff haben, oder weil die Auflösung des Dateipfads eine Schleife aufweist In meinem Fall sind diese 2 Symlinks zu Dateien, die jetzt weg sind.

Keiner von denen zählt .und ... Wenn Sie möchten, dass sie aufgenommen werden (warum sollten Sie das findtun ?), Gibt es keine andere Möglichkeit, als anzunehmen, dass sie für jedes Verzeichnis vorhanden sind, und sie systematisch zu zählen:

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 (&)/'

Was dann auf meinem gibt /usr/bin:

      2 directories
   3727 regular files
    710 symbolic links

Wenn Sie keinen Zugriff auf die GNU haben find, können Sie die erste wie folgt umschreiben:

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

Genau genommen haben wir jetzt keine Dateien gezählt, sondern Verzeichniseinträge . Ein Verzeichnis wie dieses enthält /usr/binnormalerweise mehrere Einträge, die auf dieselbe Datei verweisen. Zum Beispiel habe ich hier:

$ 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

Dies sind 3 Verzeichniseinträge (auch bekannt als Dateinamen oder Hardlinks) zu derselben Datei (der mit Inode 672252). Zum Zählen von Dateien anstelle von Verzeichniseinträgen und mit GNU findund GNU uniq(Ignorieren .und ..Dateien, die ohnehin Hardlinks zu anderen Verzeichnissen sind):

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 (&)/'

Auf meiner /usr/bingibt das:

   3711 regular files
    710 symbolic links

0

Sie haben nicht gesagt, ob Sie die gesamte Datei unter / usr / bin rekursiv oder nur unter der ersten Ebene haben möchten. Wie kommen Sie zu den Wörtern, die Sie zählen? Der übliche Weg, dies herauszufinden, besteht darin, find in wc auszuführen. So: find / usr / bin | wc -l Find listet dort alles auf, Verzeichnisse und Dateien. Wc -l zählt alle Zeilen in der Suchausgabe. Ist das eine Klassenaufgabe? Es ist in Ordnung, wenn es so ist, aber ich habe mich gefragt, warum Sie diese Informationen benötigen, damit ich die Antwort genauer anpassen kann. Bitte lassen Sie mich wissen, wenn Sie mehr benötigen. Costa


0

In Bash, ohne externe Werkzeuge.

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

In Bash, ohne externe Tools und Rekursion.

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

Beachten Sie, dass der zweite beim Rekursieren Symlinks folgt (und Symlinks zu regulären Dateien als reguläre Dateien und Symlinks zu Verzeichnissen als Verzeichnisse zählt), Dateien und Verzeichnisse im aktuellen Verzeichnis nicht zählt und weder zählt .noch ..Einträge. Möglicherweise möchten Sie die Datei von der regulären Datei unterscheiden.
Stéphane Chazelas
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.