Trova la dimensione totale di alcuni file all'interno di un ramo di directory


140

Supponiamo che ci sia una directory di memorizzazione delle immagini, per esempio, ./photos/john_doeall'interno della quale ci sono più sottodirectory, dove risiedono molti file (diciamo, *.jpg). Come posso calcolare una dimensione di riepilogo di quei file sotto il john_doeramo?

Ho provato du -hs ./photos/john_doe/*/*.jpg, ma questo mostra solo i singoli file. Inoltre, questo traccia solo il primo livello di annidamento della john_doedirectory, come john_doe/june/, ma salta john_doe/june/outrageous/.

Quindi, come potrei attraversare l'intero ramo, riassumendo le dimensioni di alcuni file?

Risposte:


183
find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

Se duè necessaria più di una chiamata perché l'elenco dei file è molto lungo, verranno riportati più totali e dovranno essere sommati.


7
trova -iname 'file *' -exec du -cb {} + | totale grep $ | cut -f1 | incolla -sd + - | bc # dimensione byte sommata
Michal Čizmazia,

3
Se il tuo sistema funziona in un'altra lingua, devi cambiare $ totale in altre parole come razem $ in polacco.
Zbyszek,

1
Puoi aggiungere LC_ALL=POSIXcome prefisso grep sempre per un totale come questo:LC_ALL=POSIX find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$
Sven

2
Se non lo stai usando -name, modifica grep in grep -P "\ttotal$"altrimenti cattura anche tutti i file che terminano con "total".
thdoan

3
@ MichalČizmazia alcune shell (ad esempio, Git Bash per Windows) non arrivano bc, quindi ecco una soluzione più portatile:find -name '*.jpg' -type f -exec du -bc {} + | grep total$ | cut -f1 | awk '{ total += $1 }; END { print total }'
thdoan

50
du -ch public_html/images/*.jpg | grep total
20M total

mi dà l'utilizzo totale dei miei .jpgfile in questa directory.

Per gestire più directory dovresti probabilmente combinarlo con in findqualche modo.

Potresti trovare utili esempi di comandi du (include anche find)


2
Questo non attraversa le directory sottostanti?
mbaitoff,

È più facile da digitare rispetto alla soluzione accettata, ma è solo a metà destra, non includerà le immagini nelle sottodirectory. Buono a sapersi se tutti i file si trovano in una directory.
gbmhunter,

@gbmhunter Penso che se aggiungi il parametro -R a -ch otterrai anche le sottodirectory mentre attraversa ricorsivamente l'albero delle directory. Al momento non sono al computer per provarlo, per confermare.
Levon,

1
Non vedo -Run'opzione su man7.org/linux/man-pages/man1/du.1.html . E non penso che un'opzione ricorsiva sarebbe di aiuto in questo caso perché la shell sta facendo l'espansione glob prima di passare gli argomenti a du.
gbmhunter

22

In primo luogo, hai bisogno di due cose:

du -ch -- **/*.jpg | tail -n 1

ottima risposta. Più semplice dell'uso di find (fintanto che * o ** corrisponde alla struttura della directory)
Andre de Miranda

Può anche gestire elenchi di file molto lunghi mentre l'utilizzo findpuò restituire risultati errati.
Eric Fournie,

l'espansione bash brace consente di misurare anche più set di caratteri jolly. du -ch -- ./{dir1,dir2}/*.jpgoppuredu -ch -- ./{prefix1*,prefix2*}.jpg
J.Money il

@EricFournie Tuttavia ho riscontrato un Argument list too longerrore durante l'elaborazione di circa 300k file di testo.
xtluo

È possibile verificare il numero massimo di argomenti per un comando (in questo caso, i nomi file restituiti dall'espansione jolly) getconf ARG_MAX. Se ne hai di più, dovrai elaborare i file uno per uno o in modo batch con un ciclo for.
Eric Fournie,

17

La risposta definitiva è:

{ find <DIR> -type f -name "*.<EXT>" -printf "%s+"; echo 0; } | bc

e versione ancora più veloce, non limitata dalla RAM, ma che richiede GNU AWK con supporto bignum:

find <DIR> -type f -name "*.<EXT>" -printf "%s\n" | gawk -M '{t+=$1}END{print t}'

Questa versione ha le seguenti caratteristiche:

  • tutte le capacità di findspecificare i file che stai cercando
  • supporta milioni di file
    • altre risposte qui sono limitate dalla lunghezza massima dell'elenco degli argomenti
  • genera solo 3 processi semplici con un throughput minimo del tubo
    • molte risposte qui generano processi C + N, dove C è una costante e N è il numero di file
  • non si preoccupa della manipolazione delle stringhe
    • questa versione non fa alcun grepping o regexing
    • bene, findfa una semplice corrispondenza jolly di nomi di file
  • formatta facoltativamente la somma in una forma leggibile (ad es. 5.5K, 176.7M, ...)
    • per fare quella append | numfmt --to=si

Mi piace la semplicità di questa risposta, anche se ha funzionato solo per me quando ho introdotto gli spazi dopo la parentesi graffa di apertura e prima della parentesi graffa di chiusura. Mi chiedo se supporterà davvero un numero di file 'infiinte' però :)
Andyb

1
@andyb grazie per il feedback, gli spazi attorno alle parentesi graffe sono effettivamente richiesti in BASH, sto usando ZSH quindi non me ne sono accorto. E il numero di file è limitato dalla RAM disponibile sul tuo sistema poiché l'utilizzo della memoria di bc aumenta lentamente man mano che i numeri scorrono.
Jan Chren - rindeal

8

Le risposte fornite fino ad ora non tengono conto del fatto che l'elenco dei file passato da find a du potrebbe essere così lungo che find divide automaticamente l'elenco in blocchi, determinando più ricorrenze di total.

È possibile grep total(locale!) E riassumere manualmente o utilizzare un comando diverso. AFAIK ci sono solo due modi per ottenere un totale generale (in kilobyte) di tutti i file trovati da find:
find . -type f -iname '*.jpg' -print0 | xargs -r0 du -a| awk '{sum+=$1} END {print sum}'

Spiegazione
find . -type f -iname '*.jpg' -print0: Trova tutti i file con estensione jpg indipendentemente dal caso (ad es. * .Jpg, * .JPG, * .Jpg ...) e visualizzali (con terminazione null).
xargs -r0 du -a: -r: Xargs chiamerebbe il comando anche senza argomenti passati, cosa che -r impedisce. -0 significa stringhe con terminazione null (non terminata da nuova riga).
awk '{sum+=$1} END {print sum}': Riassume le dimensioni del file emesse dal comando precedente

E per riferimento, l'altro modo sarebbe
find . -type f -iname '*.jpg' -print0 | du -c --files0-from=-


Suggerimento aggiuntivo: sul mio HDD con 23428 file (22323 essendo immagini) il primo metodo esegue 1 secondo mentre il secondo esegue 3,8 secondi.
Jan

Si noti che entrambi assumono un sistema GNU. Il primo presuppone che i nomi dei file non contengano caratteri di nuova riga.
Stéphane Chazelas,

Scommetto che ci è du --file0-fromvoluto più tempo perché l'hai eseguito per primo (effetto cache).
Stéphane Chazelas,

Con xargs, diversi du -apossono essere eseguiti, quindi potresti avere discrepanze se ci sono collegamenti reali.
Stéphane Chazelas,

3

Se l'elenco dei file è troppo grande e non può essere passato a una singola chiamata di du -c, su un sistema GNU, puoi fare:

find . -iname '*.jpg' -type f -printf '%b\t%D:%i\n' |
  sort -u | cut -f1 | paste -sd+ - | bc

(dimensione espressa in numero di blocchi da 512 byte). Come duse provasse a contare i collegamenti reali solo una volta. Se non ti interessano gli hardlink, puoi semplificarlo per:

(printf 0; find . -iname '*.jpg' -type f -printf +%b) | bc

Se si desidera la dimensione anziché l'utilizzo del disco, sostituire %bcon %s. La dimensione verrà quindi espressa in byte.


-bash: bc: command not foundCentos - Linux 2.6.32-431.el6.x86_64
yeya

@yeya, sembra che la tua distribuzione CentOS sia interrotta. bcè un comando POSIX non opzionale.
Stéphane Chazelas,

1

Le soluzioni menzionate finora sono inefficienti (exec è costoso) e richiedono un lavoro manuale aggiuntivo per sommare se l'elenco dei file è lungo o non funzionano su Mac OS X. La seguente soluzione è molto veloce, dovrebbe funzionare su qualsiasi sistema e restituisce la risposta totale in GB (rimuovere un / 1024 se si desidera vedere il totale in MB): find . -iname "*.jpg" -ls |perl -lane '$t += $F[6]; print $t/1024/1024/1024 . " GB"'


-iname-lssono standard / portatile, in modo da non funzionare su qualsiasi sistema sia. Inoltre non funzionerà correttamente se ci sono nomi di file o destinazioni di link simbolici che contengono caratteri di nuova riga.
Stéphane Chazelas,

Si noti inoltre che fornisce la somma delle dimensioni del file, non del loro utilizzo del disco. Per i collegamenti simbolici, indica la dimensione dei collegamenti simbolici, non i file a cui puntano.
Stéphane Chazelas,

1

Migliorare la grande risposta di SHW per farlo funzionare con qualsiasi locale, come Zbyszek ha già sottolineato nel suo commento:

LC_ALL=C find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

1

du attraversa naturalmente la gerarchia di directory e awk può eseguire il filtro in modo che qualcosa del genere possa essere sufficiente:

du -ak | awk 'BEGIN {sum=0} /\.jpg$/ {sum+=$1} END {print sum}'

Funziona senza GNU.


1
Questo è più costoso poiché comporta una statchiamata per i file che non corrispondono al modello cercato.
Legge 29

Solo questa soluzione funziona sul mio mac.
Matthias M,
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.