#1 Le 04/12/2007, à 14:41
- Strash
[bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
Salut,
Je m'embrouille toujours quand j'essaie de faire un petit script bash... ça ne fait jamais ce que je veux, une logique doit m'échapper (surtout l'histoire des pipes...)
Je cherche à lister le nombre de fichiers de chaque répertoires d'une arborescence, voilà ma démarche pour l'instant :
Pour compter le nombre de fichiers j'utilise ça :
ls -l | wc -l
ça me fournis le nombre de fichiers à 1 près
pour avoir le nombre exact il suffirai de faire une simple soustraction :
echo $((`ls -l | wc -l` - 1))
(y'a pas plus facile pour faire une soustraction en bash ?? )
donc je veux appliquer cette opération à tout les répertoires de mon arborescence...
find $dossier -type d -print0 | xargs -0 ls -l | wc -l
... le seul problème est que le wc -l (qui compte le nombre de lignes) s'applique à tout le résultat... donc j'ai juste le nombre total de fichiers (qui en plus est biaisé par le fait qu'il compte 3 lignes de plus à chaque changement de répertoire)
Comment faire pour que le wc -l s'applique à chaque exécution du ls ? Je dois m'y prendre mal...
Merci
PS : j'ai aussi essayé avec une boucle for :
for d in `find $dossier -type d`
do
ls -l $d | wc -l
done
Mais du coup les espaces dans les noms de dossier font que la plupart du temps le ls ne reconnais pas le dossier... comment passer outre ce problème d'espace ??
Dernière modification par Strash (Le 04/12/2007, à 14:45)
Hors ligne
#2 Le 04/12/2007, à 15:26
- bertrand0
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
Si tu veux juste compter les fichiers mais pas les dossiers:
find mondossier -not -type d | wc -l
Si tu veux compter dossiers et fichiers:
find mondossier | wc -l
Ceux qui écrivent comme ils parlent, quoiqu'ils parlent très bien, écrivent mal.
Buffon, Discours sur le style
Hors ligne
#3 Le 04/12/2007, à 15:37
- Yannick_LM
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
Salut,
Il me semble que tu complique la vie pour rien en utilsant l'option -l.
(tu rajoutes des infos dont tu n'as que faire si tu veux juste compter le nombre de fichiers, et une ligne total, dont tu n'as pas besoin)
Bon, alors, pour les pipes, ils s'exécutent les uns après les autres, (de la gauche vers la droite), là , j'ai pas vraiment d'idées...
Donc, effectivement, le mieux est de passer par une boucle :
IFS="
"
for d in `find $dossier -type d`
do
echo $d
echo `ls $d | wc -l`
done
La ligne avec IFS et la pour dire que, pour le retour de find, on va considérer que les noms de fichiers sont séparés par des sauts de ligne et non par des simples espaces (comme c'est le cas pour la ligne de commande) ;
J'ai aussi rajouté une ligne echo pour que tu saches de quel dossier il s'agit ...
Voilà .
EDIT :
@bertrand0 : il me semble que tu ne réponds pas à la question posée, ou alors c'est moi qui l'ai mal comprise ...
@Strash
Avec une arborescence de type:
a
1
b
2
3
Le résultat que tu veux avoir est-il bien celui-ci ?
.
3
./b
1
./a
2
Dernière modification par Yannick_LM (Le 04/12/2007, à 15:49)
Trucs et astuces pour Vim
Ma web page avec des trucs dessus ...
Hors ligne
#4 Le 04/12/2007, à 15:50
- bertrand0
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
Ah! okay, alors ce serait plutà´t qq chose comme:
find mondossier -type d -printf "echo '%P'; find '%p' -maxdepth 1 | wc -l;\n" | sh
On peut éveltuellement virer le maxdepth 1 pour que les contenus des sous-répertoires soient inclus dans les totaux des répertoires contenants.
Si les fichiers à lister risquent de contenir le caractère ', on peut utiliser plutà´t (les noms de fichiers ne doivent contenir ni *, ni caractères spéciaux genre newline ou tabulation):
find /home/bertrand -type d -printf "echo *%P*; find *%p* -maxdepth 1 | wc -l;\n" | sed "s/'/\\\'/g;s/\*/'/g" | less
Dernière modification par bertrand0 (Le 04/12/2007, à 16:39)
Ceux qui écrivent comme ils parlent, quoiqu'ils parlent très bien, écrivent mal.
Buffon, Discours sur le style
Hors ligne
#5 Le 04/12/2007, à 16:30
- Strash
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
Merci pour vos réponses rapides !
Pour préciser un peu ce que je veux faire :
J'aime bien avoir ma collection de musique bien triée, que ce soit mes CDs sur l'étagère ou son équivalent numérique sur mon PC.
Pour cela j'utilise Amarok qui fait du super boulot, mais parfois je renomme un album ou j'en supprime un (et après j'utilise la gestion des fichiers d'amarok pour qu'il fasse la modification dans mon arborescence), et du coup il reste parfois des dossiers avec seulement 1 ou 2 fichiers (le cover.png par exemple). J'aimerai donc faire un script qui me repère ces dossiers là , pour que je puisse les supprimer et ainsi avoir une collection toute propre à transférer à mon balladeur ! (je suis compliqué non ? )
Donc après avoir listé le nombre de fichiers de chaque dossier, je comptais trier cette liste par nombre de fichier (dans l'ordre croissant).
Je vais lire et utiliser vos réponses puis je reviendrais sûrement avec d'autres questions
@Yannick_LM > la forme de ma sortie serais dans l'idéal de ce style :
1 Chemin/d'un/dossierquicontiens1seulfichier
1 Chemin/d'un/autredossierquicontiens1seulfichier
2 Chemin/d'un/dossierquicontiens2fichiers
2 Autre/Chemind'undossierquicontiens2fichiers
...
...
126 Chemin/d'un/dossier/qui/contiens/126/fichiers
Je préfère y aller progressivement et avec mon raisonnement pour pouvoir progresser et voir si j'y arrives avec mes méthodes.
@Bertrand0 > Je ne comprends pas comment fonctionne la ligne que tu as donné, tu pourrais détailler ? Merci
Dernière modification par Strash (Le 04/12/2007, à 16:34)
Hors ligne
#6 Le 04/12/2007, à 16:47
- bertrand0
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
"find mondossier -type d" liste tous les dossiers, sous-dossiers, etc. dans mondossier. Grà¢ce -printf, pour chaque occurence, le commande renvoie 1 ligne:
echo 'nom_du_dossier_encours_relatif'; find 'nom_du_dossier_en_cours_absolu' -maxdepth 1 | wc -l
Cela génère donc une série de commandes shell exécutées au fur et à mesure par sh en fin de ligne:
le echo affiche le nom du dossier sur une ligne
le find |wc affiche le nombre de fichiers et dossiers dans le répertoire (si on met maxdepth 1. Sinon il affiche les fichiers et dossiers dans le répertoire et ses sous-répertoires. On peut aussi ajouter '-type f' si on ne veux que les fichiers et pas les dossiers dans le compte)
Ceux qui écrivent comme ils parlent, quoiqu'ils parlent très bien, écrivent mal.
Buffon, Discours sur le style
Hors ligne
#7 Le 04/12/2007, à 19:33
- Yannick_LM
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
Bah, il suffit de modifier le script pour qu'il affiche ce que tu veux, du genre :
#!/bin/bash
IFS="
"
for d in `find $dossier -type d`
do
echo $d
echo `ls $d | wc -l`
done
echo `ls $d | wc -l` $d
Tu mets ça dans un fichier ~/recherche.sh, tu le rends exécutable, tu vas dans le répertoire de ta musique, et :
~/recherche.sh | sort
Et voilà .
Je te laisse regarde comment de débrouiller avec les 128 lignes.
(indice : head)
Dernière modification par Yannick_LM (Le 04/12/2007, à 19:34)
Trucs et astuces pour Vim
Ma web page avec des trucs dessus ...
Hors ligne
#8 Le 04/12/2007, à 23:42
- Strash
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
@Bertrand0 > Merci pour les explication, j'ai découvert plein de trucs ! Mais je ne suis pas trop fan des scripts en une seule ligne qui sont un peu trop obscurs (mais peut-être plus efficaces ?)
Je préfère un code aéré que je puisse modifier 2 ans plus tard sans me prendre la tête pendant deux heures...
@Yannick_LM > J'avais fait les modifications de ton script initial de mon coté et ça avais donné :
#!/bin/sh
dossier="/home/user/Musique/"
IFS="
"
for d in `find $dossier -mindepth 2 -type d`
do
if [[ `ls $d | wc -l` -lt 10 ]]
then
echo 00`ls $d | wc -l` $d
elif [[ `ls $d | wc -l` -lt 100 ]]
then
echo 0`ls $d | wc -l` $d
else
echo `ls $d | wc -l` $d
fi
done | sort -r
Par contre en lisant ton post j'ai vu que tu parles de la fonction head... j'ai regardé le man et j'ai pas trop compris en quoi ça pourrais rendre le tri moins "con". J'ai utilisé une ruse en rajoutant des 0, mais si tu as une solution plus propre (et qui marcherais pour tout nombre sans avoir à rajouter une tonne de elif) ça pourrais être utile dans d'autres applications (pis ça me ferais une fonction de plus à mon actif )
Hors ligne
#9 Le 05/12/2007, à 18:38
- Yannick_LM
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
Ah, oui, tiens, j'avais oublié ce "détail".
(ça m'apprendra à ne pas tester mes scripts jusqu'au bout)
En fait, par défaut, sort trie par ordre alphabétique. C'est pas ça que tu veux.
Regarde du cà´té des options de sort (man sort), tu devrais pouvoir trouver ton bonheur.
Sinon, head, c'est juste parce que tu recherches les fichiers pas trop pleins, donc ceux qui sont au début de la liste, c'est tout.
Tu peux aussi décider de n'afficher que ceux qui ont moins de tant éléments, par exemple.
Trucs et astuces pour Vim
Ma web page avec des trucs dessus ...
Hors ligne
#10 Le 06/12/2007, à 18:19
- Strash
Re : [bash] Je n'arrive pas à bien utiliser xargs avec des pipes...
Merci pour tout, j'ai réussi à faire un petit script qui a pour l'instant les fonctions que je voulais, et j'ai ainsi nettoyé mon répertoire sans danger pour ma collection.
Le script final (pour ceux que ça pourrais intéresser) :
#!/bin/sh
dossier="$HOME/Musique/"
echo "Liste des dossiers vides"
find $dossier -type d -empty
IFS="
"
echo " "
echo "Liste du contenu des dossiers qui ne contiennent pas de MP3, de MPC, de MID, de WMA ou de OGG"
for d in `find $dossier -type d`
do
if [[ `ls -l $d | grep -v drwx | wc -l` -gt 1 ]]
then
echo `ls $d | wc -l` $d : `ls $d`
fi
done | egrep -i -v .[mwo][pmgi][a3gcd]
echo " "
echo "Création de la liste du nombre de fichiers par dossier : liste_nbr_fich (Ctrl+C pour arréter)"
for d in `find $dossier -type d`
do
echo `ls $d | wc -l` $d
done | sort -g > liste_nbr_fich
Dernière modification par Strash (Le 06/12/2007, à 18:24)
Hors ligne