Come posso usare word counter ( wc
) e piping per contare quanti file o directory ci sono nella /usr/bin
directory?
Come posso usare word counter ( wc
) e piping per contare quanti file o directory ci sono nella /usr/bin
directory?
Risposte:
Un approccio sarebbe quello di utilizzare ls
per darci un elenco dei file, ma vogliamo che questo elenco sia garantito per mostrare solo 1 file o directory per riga. L' -1
interruttore farà questo per noi.
$ ls -1
dir1
dir2
dir3
fileA
fileB
fileC
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 -l
per contare il numero di righe, che corrispondono a un file o una directory ls -1
nell'output.
$ ls -1 | wc -l
6
(notare tuttavia che non include i file nascosti)
Per contare file o directory devi modificare leggermente la tua tattica. In questo caso lo userò ls -l
poiché mostra cos'è una directory e cos'è un file.
$ 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 grep
per 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 -l
nuovo per contare quanto sopra:
# directories
$ ls -l | grep "^d" | wc -l
3
# regular files
$ ls -l | grep "^-" | wc -l
3
Tuttavia, puoi evitare del wc
tutto e utilizzare grep
l' -c
opzione:
$ 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 ...).
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
.
$ find /usr/bin | wc -l
4632
(anche se sopra /usr/bin
è incluso nel conteggio)
Le stesse tecniche che ho usato sopra potrebbero essere usate ls
per fare qualcosa di simile ma ls
generalmente non è un buon strumento per analizzare l'output. find
d'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 find
include file nascosti (tranne .
e ..
)).
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 wc
e ls
non contenderebbero con questi, quindi usali con questo in mente.
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 wc
conta 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 find
la capacità di stampare qualcos'altro al posto di ciascun file che trova e quindi contarli.
$ 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
.
/usr/bin
saranno 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.
ls -l
o ls -1
romperà b / c stiamo contando le righe, non le parole! L' find
può rompersi, ma ancora una volta, stiamo contando le linee non parole.
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 wc
riguarda. A meno che non ls
sostituisca le nuove righe con qualche altro personaggio (non credo che lo faccia, ma ancora una volta non sono in grado di testare).
wc -c
un problema quando si contano i periodi?
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/bin
mio 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 find
non è 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 find
che 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/bin
genere 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 find
e 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
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
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
.
né le ..
voci. Potresti voler disambiguare il file rispetto al file normale.