web-dev-qa-db-fra.com

Utilisation du disque de fichiers dont les noms correspondent à une expression régulière, sous Linux?

Donc, dans de nombreuses situations, je voulais un moyen de savoir combien d'espace disque est utilisé par quoi, donc je sais de quoi me débarrasser, convertir dans un autre format, stocker ailleurs (comme des DVD de données), passer à une autre partition, etc. Dans ce cas, je regarde une partition Windows à partir d'un support de démarrage SliTaz Linux .

Dans la plupart des cas, ce que je veux, c'est la taille des fichiers et des dossiers, et pour cela j'utilise NCurses ncd :

ncdu

Mais dans ce cas, je veux un moyen d'obtenir la taille de tous les fichiers correspondant à une expression régulière. Un exemple d'expression régulière pour les fichiers .bak:

.*\.bak$

Comment puis-je obtenir ces informations, en considérant un Linux standard avec le noyau GNU utilitaires ou BusyBox ?

Edit: La sortie est destinée à être analysée par un script.

39
Camilo Martin

Je suggère quelque chose comme: find . -regex '.*\.bak' -print0 | du --files0-from=- -ch | tail -1

Quelques notes:

  • Le -print0 option pour find et --files0-from pour du sont là pour éviter les problèmes avec les espaces dans les noms de fichiers
  • L'expression régulière est mise en correspondance avec l'ensemble du chemin, par ex. ./dir1/subdir2/file.bak, pas seulement file.bak, donc si vous le modifiez, tenez-en compte
  • J'ai utilisé le drapeau h pour que du produise un format "lisible par l'homme" mais si vous voulez analyser la sortie, vous pouvez être mieux avec k (utilisez toujours des kilo-octets)
  • Si vous supprimez la commande tail, vous verrez en outre la taille de fichiers et de répertoires particuliers

Sidenote: un bel outil graphique pour découvrir qui a mangé votre espace disque est FileLight . Il ne fait pas de regex, mais est très pratique pour trouver de gros répertoires ou des fichiers obstruant votre disque.

47
Michał Kosmulski

du est ma réponse préférée. Si vous avez une structure de système de fichiers fixe, vous pouvez utiliser:

du -hc *.bak

Si vous devez ajouter des sous-répertoires, ajoutez simplement:

du -hc *.bak **/*.bak **/**/*.bak

etc

Cependant, ce n'est pas une commande très utile, donc en utilisant votre recherche:

TOTAL=0;for I in $(find . -name \*.bak); do  TOTAL=$((TOTAL+$(du $I | awk '{print $1}'))); done; echo $TOTAL

Cela fera écho à la taille totale en octets de tous les fichiers que vous trouvez.

J'espère que cela pourra aider.

25
MaddHacker

Les solutions précédentes ne fonctionnaient pas correctement pour moi (j'ai eu des problèmes de tuyauterie du) mais les suivantes ont très bien fonctionné:

find path/to/directory -iregex ".*\.bak$" -exec du -csh '{}' + | tail -1

L'option iregex est une expression régulière insensible à la casse. Utilisez regex si vous voulez qu'il soit sensible à la casse.

Si vous n'êtes pas à l'aise avec les expressions régulières, vous pouvez utiliser les drapeaux iname ou name (le premier étant insensible à la casse):

find path/to/directory -iname "*.bak" -exec du -csh '{}' + | tail -1

Dans le cas où vous souhaitez la taille de chaque match (plutôt que le total combiné), laissez simplement la commande piped tail:

find path/to/directory -iname "*.bak" -exec du -csh '{}' +

Ces approches évitent le problème de sous-répertoire dans la réponse de @MaddHackers.

J'espère que cela aide les autres dans la même situation (dans mon cas, trouver la taille de toutes les DLL dans une solution .NET).

3
ben.snape

Exécutez ceci dans un Bourne Shell pour déclarer une fonction qui calcule la somme des tailles de tous les fichiers correspondant à un modèle d'expression régulière dans le répertoire actuel:

sizeofregex() { IFS=$'\n'; for x in $(find . -regex "$1" 2> /dev/null); do du -sk "$x" | cut -f1; done | awk '{s+=$1} END {print s}' | sed 's/^$/0/'; unset IFS; }

(Alternativement, vous pouvez le mettre dans un script.)

tilisation:

cd /where/to/look
sizeofregex 'myregex'

Le résultat sera un nombre (en Kio), y compris 0 (s'il n'y a aucun fichier correspondant à votre expression régulière).

Si vous ne voulez pas qu'il regarde dans d'autres systèmes de fichiers (disons que vous voulez chercher tous les .so fichiers sous /, qui est une monture de /dev/sda1, mais pas sous /home, qui est une monture de /dev/sdb1, ajouter un -xdev paramètre à find dans la fonction ci-dessus.

3
Camilo Martin

Si vous êtes d'accord avec les motifs globaux et que vous êtes uniquement intéressé par le répertoire courant:

stat -c "%s" *.bak | awk '{sum += $1} END {print sum}'

ou

sum=0
while read size; do (( sum += size )); done < <(stat -c "%s" *.bak)
echo $sum

Le %s la directive stat donne des octets et non des kilo-octets.

Si vous voulez descendre dans des sous-répertoires, avec bash version 4, vous pouvez shopt -s globstar et utilisez le modèle **/*.bak

1
glenn jackman

La réponse acceptée suggère d'utiliser

find . -regex '.*\.bak' -print0 | du --files0-from=- -ch | tail -1

mais cela ne fonctionne pas sur mon système car du ne connaît pas --files-0-from option sur mon système. Seul GNU du connaît cette option, elle ne fait pas partie de la POSIX Standard (donc vous ne la trouverez pas dans FreeBSD ou macOS), ni le trouverez-vous sur systèmes Linux basés sur BusyBox (par exemple la plupart des systèmes Linux embarqués) ou sur tout autre système Linux qui n'utilise pas la version GNU du .

Ensuite, il y a une réponse suggérant d'utiliser:

find path/to/directory -iregex .*\.bak$ -exec du -csh '{}' + | tail -1

Cette solution fonctionnera tant qu'il n'y aura pas trop de fichiers trouvés, comme + signifie que find va essayer d'appeler du avec autant de hits que possible en un seul appel, cependant, il peut y avoir un nombre maximum d'arguments (N) pris en charge par un système et s'il y en a plus de hits que cette valeur, find appellera du plusieurs fois, divisant les hits en groupes inférieurs ou égaux à N éléments chacun et dans ce cas, le résultat sera incorrect et ne montrera que la taille de le dernier du appel.

Enfin, il existe une réponse en utilisant stat et awk, ce qui est une bonne façon de le faire, mais il s'appuie sur Shell globbing d'une manière que seul Bash 4.x ou version ultérieure prend en charge. Il ne fonctionnera pas avec les anciennes versions et s'il fonctionne avec d'autres shells est imprévisible.

Une solution conforme POSIX (fonctionne sur Linux, macOS et toutes les variantes BSD), qui ne souffre d'aucune limitation et qui fonctionnera sûrement avec chaque Shell serait:

find . -regex '.*\.bak' -exec stat -f "%z" {} \; | awk '{s += $1} END {print s}'
1
Mecki