Come usare wc e piping per trovare quanti file e directory ci sono in una determinata directory?


10

Come posso usare word counter ( wc) e piping per contare quanti file o directory ci sono nella /usr/bindirectory?


Questo compito ?? Va bene chiedere aiuto, basta identificarlo come tale, se lo è.
slm

sì, ma postò qui per avere un'idea di come realizzare qualcosa, dato che sono nuovo di Linux e può essere molto complicato. E ho già risolto la domanda sopra con questo comando
contanti

ls / bin / usr / bin | ordina | uniq | wc -
contanti

np. Va benissimo chiedere aiuto! Basta etichettarlo in modo che la gente lo sappia, tutti qui sono di solito felici di aiutare le persone che stanno cercando di imparare i punti più fini di Unix.
slm

Risposte:


13

Un approccio sarebbe quello di utilizzare lsper darci un elenco dei file, ma vogliamo che questo elenco sia garantito per mostrare solo 1 file o directory per riga. L' -1interruttore farà questo per noi.

$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC

Esempio

Creare i dati di esempio sopra in una directory vuota.

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

Controllalo:

$ ls
dir1  dir2  dir3  fileA  fileB  fileC

Ora per contare puoi usare wc -lper contare il numero di righe, che corrispondono a un file o una directory ls -1nell'output.

$ ls -1 | wc -l
6

(notare tuttavia che non include i file nascosti)

Conteggio di file o directory, ma non insieme

Per contare file o directory devi modificare leggermente la tua tattica. In questo caso lo userò ls -lpoiché mostra cos'è una directory e cos'è un file.

Esempio

$ 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

Quindi possiamo usare grepper filtrare directory o non directory in questo modo:

# 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

Ora basta usare di wc -lnuovo per contare quanto sopra:

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

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

Tuttavia, puoi evitare del wctutto e utilizzare grepl' -copzione:

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

(di nuovo, i file nascosti non sono inclusi. Nota che le directory e il normale sono due tipi di file. Ce ne sono molti altri come named pipe, collegamenti simbolici, dispositivi, socket ...).

ricorsione

Se hai bisogno di trovare i file e le directory in modo ricorsivo /usr/bin, probabilmente vorrai cambiare completamente le tattiche e utilizzare un altro strumento chiamato find.

Esempio

$ find /usr/bin | wc -l
4632

(anche se sopra /usr/binè incluso nel conteggio)

Le stesse tecniche che ho usato sopra potrebbero essere usate lsper fare qualcosa di simile ma lsgeneralmente non è un buon strumento per analizzare l'output. findd'altra parte è stato creato per questo e offre opzioni per trovare file o directory.

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

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

(nota che questa volta findinclude file nascosti (tranne .e ..)).

a capo?

Non ho mai capito perché un personaggio newline sia un personaggio legale da usare quando si creano nomi di file o directory. Quindi i metodi discussi sopra usando wce lsnon contenderebbero con questi, quindi usali con questo in mente.

Esempio

Crea una directory e un nome file con newline.

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

ls li mostra correttamente:

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

Ma wcconta le directory e i file che contengono newline come 2 elementi, non uno.

$ ls -1 | wc -l
10

Un metodo per aggirare questo problema, se si utilizza l'implementazione GNU di findè utilizzare findla capacità di stampare qualcos'altro al posto di ciascun file che trova e quindi contarli.

Esempio

$ find . -printf . | wc -c
9

Qui stiamo tutto ritrovamento nella directory corrente (ad eccezione ..), e la stampa di un punto ( .) per ciascuno, e poi contare i punti che utilizzano wc's capacità di contare i byte invece di linee, wc -c.

Riferimenti


Mentre i file in /usr/binsaranno tutti ben formattati (e non contengono spazi, quindi tecnicamente potresti anche solo echo * | wc -w), vale la pena notare che tutti questi si romperanno su nomi di file contenenti nuove righe.
evilsoup,

@evilsoup - no, non credo che ls -lo ls -1romperà b / c stiamo contando le righe, non le parole! L' findpuò rompersi, ma ancora una volta, stiamo contando le linee non parole.
slm

Quello che voglio dire è che questo (penso, sono su Windows in questo momento quindi non posso testarlo) si romperà se i file contengono nuove righe . Quindi touch $'foo\nbar'all'interno di una directory vuota seguita da uno dei tuoi comandi (diciamo ls -1 | wc -l) riporterai due file anziché uno - perché quel file è composto da due righe per quanto wcriguarda. A meno che non lssostituisca le nuove righe con qualche altro personaggio (non credo che lo faccia, ma ancora una volta non sono in grado di testare).
evilsoup,

@evilsoup - carattere corretto, newline. è un carattere legale. per i nomi di file e i metodi non sarebbero in grado di competere correttamente con questi tipi di nomi di file.
slm

@StephaneChazelas - è wc -cun problema quando si contano i periodi?
slm

5

Se vuoi ottenere una suddivisione del numero di ogni tipo di file in modo ricorsivo sotto qualche dir, con GNU find, puoi fare:

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

Sul /usr/binmio sistema, questo dà:

   3727 regular files
    710 symbolic links

Su /dev:

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

Per i collegamenti simbolici, se preferisci contarli come il tipo di file a cui puntano anziché symbolic links, puoi cambiarlo 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 (&)/'

Che ora dà per il mio /usr/bin:

      1 directories
   4434 regular files
      2 broken symbolic links

(un collegamento simbolico non funzionante è un collegamento simbolico a un file per il quale findnon è possibile determinare il tipo perché il file non esiste oppure si trova in una directory a cui non si ha accesso o è presente un ciclo nella risoluzione del percorso del file Nel mio caso, quei 2 in cui collegamenti simbolici ai file che ora sono andati).

Nessuno di questi conta .e ... Se li volevi inclusi (perché dovresti?), Non c'è altro modo findche supporre che siano lì per ogni directory e contarli sistematicamente:

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

Che poi dà sul mio /usr/bin:

      2 directories
   3727 regular files
    710 symbolic links

Se non hai accesso a GNU find, puoi riscrivere il primo come:

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

Ora, a rigor di termini, non abbiamo contato i file ma le voci della directory . Una directory come in /usr/bingenere ha diverse voci che puntano allo stesso file. Ad esempio, qui ho:

$ 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

Quelle sono 3 voci di directory (alias nomi di file o hard link) nello stesso file (quello con inode 672252. Per contare i file invece delle voci di directory e con GNU finde GNU uniq(ignorando .e ..file che comunque sono hard link ad altre directory):

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

Sul mio /usr/bin, ciò dà:

   3711 regular files
    710 symbolic links

0

Non hai detto se vuoi tutti i file in / usr / bin ricorsivamente o appena sotto il primo livello. Inoltre, come hai intenzione di ottenere le parole che stai contando? Il solito modo per scoprirlo è eseguire find in wc. In questo modo: find / usr / bin | wc -l Find elencherà tutto lì, directory e file. Wc -l conterà tutte le righe nell'output find. È un compito di classe? Va bene se lo è, ma mi chiedevo perché avevi bisogno di queste informazioni in modo da poter personalizzare la risposta con più attenzione. Per favore fatemi sapere se avete bisogno di più. Costa


0

In bash, senza strumenti esterni.

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

In bash, senza strumenti esterni e ricorsione.

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

Si noti che il secondo seguirà i collegamenti simbolici durante la ricorrenza (e conteggerebbe i collegamenti simbolici ai file regolari come file regolari e i collegamenti simbolici alle directory come directory), non conterebbe i file e le directory nella directory corrente e non conterebbe .né le ..voci. Potresti voler disambiguare il file rispetto al file normale.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.