Trova le directory che contengono un determinato numero di file


13

Speravo di poterlo fare con il findcomando ma non riesco a vedere nessun test nel manuale per fare quello che voglio. Vorrei poter trovare nella directory di lavoro tutte le directory che contengano meno, più o esattamente il conteggio specificato.

find . -filecount +10 # any directory with more than 10 entries
find . -filecount 20 # any directory with exactly 20 entries

Ma purtroppo non esiste tale opzione.


prova qualcosa del tipo "ls -al | wc -l | grep"
Vanadis,

Risposte:


16

Puoi provare questo, per ottenere i nomi delle directory secondarie e il numero di file / directory che contengono:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \;

Se vuoi fare lo stesso per tutte le sottodirectory (ricerca ricorsiva) usa invece:

find . -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \;

Per selezionare quelle directory che hanno esattamente 10 file:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
  awk '$NF==10'

10 o più:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
 awk '$NF>=10'

10 o meno:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
 awk '$NF<=10'

Se si desidera mantenere solo il nome della directory (ad esempio se si desidera reindirizzarlo a un altro processo a valle come suggerito da @evilsoup) è possibile utilizzare questo:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{}\t'; ls '{}' | wc -l" \; | 
 awk -F"\t" '$NF<=10{print $1}'

1
Penso che potrebbe essere utile includere il comando awk per tagliare il conteggio dei file (ovvero l'ultima colonna delimitata da spazi bianchi), nel caso in cui l'interrogante voglia reindirizzare l'output a qualcos'altro.
evilsoup,

1
@evilsoup buona idea, fatto.
terdon,

Supportare spazi bianchi e caratteri speciali nei nomi delle directory; prova a invertire l'uso delle virgolette singole e doppie in quanto tali:find . -type d -exec bash -c 'echo -ne "{} "; ls "{}" | wc -l' \; | awk '$NF<=10'
Håvard Geithus,

3

Per elencare le sottodirectory immediate contenenti esattamente i $NUM file.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]==num) printf "%s\n", line}'

Per elencare le sottodirectory immediate contenenti file maggiori di $NUM.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]>num) printf "%s\n", line}'

Per elencare le sottodirectory immediate contenenti meno di $NUMfile.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]<num) printf "%s\n", line}'

Gli elementi sono chiusi da un carattere null \0, quindi i nomi dei file che contengono nuove righe o altri tipi di spazi bianchi verranno interpretati correttamente. Il %hstamperà ogni file di dirname. awkquindi utilizza un array per contare quante volte incontra ogni directory, stampandola se le condizioni sono soddisfatte.

Notare che nessuno dei suddetti comandi visualizzerà directory contenenti zero file. Si noti inoltre che per file mi riferisco a file regolari, non a collegamenti, directory, socket, blocchi, named pipe, eccetera.

Ho provato a farlo nel modo più semplice possibile. Se si desidera trovare sottodirectory ricorsive o i relativi file, è necessario un comando modificato. Ci sono troppe possibilità per elencarle tutte.


2

Prova questo:

[`trova. | wc -l` -eq 10] && echo "Found"

[`trova. | wc -l` -gt 10] && echo "Found"

[`trova. | wc -l` -lt 10] && echo "Found"

In questo esempio è possibile verificare se la directory CURRENT contiene esattamente 10, più di 10 e meno di 10 file / directory. Se devi controllare un sacco di directory, usa semplicemente loop.


La tua soluzione conta anche la directory corrente ( .), potresti voler modificare di conseguenza.
terdon,

Mi piace la spinta di questa risposta (perché sono un ghiottone per fare cose nella shell), ma sarebbe meglio usare wc -l < <(printf %s\\n ./*)o printf %s\\n ./* | wc -lall'interno del test, per evitare una findchiamata non necessaria . Questo eviterà anche il problema notato da @terdon, incluso .nel risultato. Tuttavia, si imbatterà anche nel problema di ignorare i file che iniziano con un .; Lo risolverei con shopt -s dotglob(per far corrispondere i file globs a partire da a ., ma non .o ..).
evilsoup,

@terdon Non è importante. Non è la soluzione finale, solo un esempio, un'idea. Puoi -1 o cambiare da 10 a 11 nella versione finale.
settembre

Lo so, e l'idea è buona, ecco perché ho dato il suggerimento.
terdon,

@ terdon. Grazie. Ci possono essere molti requisiti diversi, come: contare solo i file ma non le directory, i collegamenti o i collegamenti reali. Contare o meno i file nelle sottodirectory. Conta i file nascosti (come .bashrc) ... ... così la tua espressione può essere veeeeery a picco. :)
Settembre
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.