Shell : compter le nombre de fichiers dans un dossier..compliqué [Fermé]

Signaler
Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016
-
Messages postés
1156
Date d'inscription
lundi 2 mai 2016
Statut
Contributeur
Dernière intervention
22 décembre 2020
-
Bonjour,


Voilà j'aimerais passer une commande, ou suite de commandes, ou faire un script pour compter le nombre de fichiers d'un dossier, et si le "ls" échoue, afficher une erreur. Je précise bien que je souhaite effectuer le ls et afficher une erreur s'il échoue, et non pas déterminer à l'avance si le ls va échouer.

Pour tester j'ai créé :
Un dossier nommé aa contenant un seul fichier nommé "h h"
Un dossier nommé bb ne contenant aucun fichier

J'utilise ls $dossier | wc -l pour connaitre le nombre de fichiers.

Problème : si "ls" échoue, le wc -l lancé en parallèle renvoie quand même 0.

GNU-bash-4.1.2 $ ls
aa bb
GNU-bash-4.1.2 $ ls aa |wc -l
1
GNU-bash-4.1.2 $ ls bb |wc -l
0
GNU-bash-4.1.2 $ ls cc | wc -l
ls: impossible d'accéder à cc: Aucun fichier ou dossier de ce type
0
GNU-bash-4.1.2 $


J'ai essayé de stocker le résultat du "ls" dans une variable, mais dans ce cas je perds le dernier saut de ligne du résultat du "ls", et le wc -l donne un mauvais résultat.

Avez-vous une meilleure idée ? Comment feriez-vous pour solutionner ce problème ?
Merci :)

5 réponses

Messages postés
36299
Date d'inscription
dimanche 7 novembre 2010
Statut
Contributeur
Dernière intervention
27 janvier 2021
5 967
Salut,

Peut-être pas la solution la plus optimisée :

ls cc >/dev/null && ls cc  | wc -l

Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016
5
:)
J'y avais songé à un moment mais sans tester puisque ça fait faire 2 fois le ls et je n'aimais pas ça
Mais je suis forcé d'en reconnaître l'efficacité

GNU-bash-4.1.2 $ ls aa>/dev/null && ls aa | wc -l || echo ERREUR
1
GNU-bash-4.1.2 $ ls bb>/dev/null && ls bb | wc -l || echo ERREUR
0
GNU-bash-4.1.2 $ ls cc>/dev/null && ls cc | wc -l || echo ERREUR
ls: impossible d'accéder à cc: Aucun fichier ou dossier de ce type
ERREUR
GNU-bash-4.1.2 $


Je prends !
Merci !

(Je vais essayer de l'adapter aussi avec un find pour compter réellement le nombre de fichier y compris d'éventuels fichiers avec un "\n" dans le nom. S'il n'y a pas d'autre commande plus simple dédiée à celà)
Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016
5
Rebonjour,
J'aimerais quand même trouver une solution propre.

Je n'y arrive pas.
J'ai essayé de bien des façons, sans succès, voici ma dernière tentative (affreuse) :
if liste="$(find aa -type f -print0)"; then od -c <<<"$liste" | fgrep -o '\0' |wc -l; else echo "ERREUR"; fi

Je crois pourtant essayer de faire quelque chose de simple, non ? Compter proprement le nombre de fichiers d'un dossier.
Voyez-vous une autre manière de faire svp ?

Mes difficultés :
- passer par une variable temporaire supprime l'information du dernier saut de ligne et tous les caractères binaires NULL.
(J'aimerais ne pas avoir à créer de fichiers temporaires juste pour ça)
- mettre des commandes entre "|" dans une commande entre $( ) fait que je n'arrive pas à savoir s'il y a eu une erreur à l'exécution de la première commande, même avec $PIPESTATUS.
Messages postés
3211
Date d'inscription
dimanche 17 janvier 2010
Statut
Membre
Dernière intervention
22 juin 2016
201
Bonjour,

find /chemin/ -type f est pour des fichiers utilise -type d pour les répertoirs
Messages postés
3211
Date d'inscription
dimanche 17 janvier 2010
Statut
Membre
Dernière intervention
22 juin 2016
201
exemple pour le répertoire courant si on veux s'avoir combien de répertoire:

find . -type d -name "*" | wc -l
Messages postés
1156
Date d'inscription
lundi 2 mai 2016
Statut
Contributeur
Dernière intervention
22 décembre 2020
143
Salut,

Le but final est-il de juste compter le nombre total de fichiers contenus dans les différents répertoires ?
Messages postés
18240
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
30 novembre 2020
5 209
hello
$ ls
aa bb
$ ls aa bb 2>/dev/null| (a=$(wc -l); [[ $a -eq 0 ]] && echo erreur || echo $a )
2
$ ls bb 2>/dev/null| (a=$(wc -l); [[ $a -eq 0 ]] && echo erreur || echo $a )
1
$ ls cc 2>/dev/null| (a=$(wc -l); [[ $a -eq 0 ]] && echo erreur || echo $a )
erreur
Messages postés
18240
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
30 novembre 2020
5 209
les puristes rétorqueront que je ne teste pas l'erreur de ls mais l'absence de fichier
Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016
5
Salut, effectivement ça ne va pas là :/ Il renvoie une erreur s'il y a 0 fichiers au lieu de renvoyer le nombre de fichiers (0).

C'est bien ça UnGnu : je souhaite afficher le nombre de fichiers qu'il y a dans un dossier, que ce soit 0 ou n. Mais si la commande qu'on utilise pour connaître le contenu du dossier échoue (peu importe la raison) alors on affiche ERREUR et non pas 0. Un nom de fichier peut contenir n'importe quel caractère saut le caractère NULL ou "/", d'où l'idée de passer par un find -print0, mais dans ce cas je n'arrive pas à compter les caractères NULL si je mets le résultat dans une variable.
Messages postés
1156
Date d'inscription
lundi 2 mai 2016
Statut
Contributeur
Dernière intervention
22 décembre 2020
143
Il existe la commande "tree" (pour peu qu'elle soit installée) qui fait ça très bien.

$ ls
aa bb cc dd

$ ls -R
.:
aa bb cc dd

./aa:
fich1 fich2 fich3

./bb:

./cc:
hh?hh

./dd:
fich script.sed

$ tree
.
├── aa
│   ├── fich1
│   ├── fich2
│   └── fich3
├── bb
├── cc
│   └── hh\012hh
└── dd
├── fich
└── script.sed

4 directories, 6 files

$ tree --prune
.
├── aa
│   ├── fich1
│   ├── fich2
│   └── fich3
├── cc
│   └── hh\012hh
└── dd
├── fich
└── script.sed

3 directories, 6 files

$ tree | tail -1 | grep -Po ', \K[^ ]*'
6

$ tree aa | tail -1 | grep -Po ', \K[^ ]*'
3

Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016
5
Salut,
non j'avais écrit : je souhaite afficher le nombre de fichiers qu'il y a dans un dossier, que ce soit 0 ou n. Mais si la commande qu'on utilise pour connaître le contenu du dossier échoue (peu importe la raison) alors on affiche ERREUR et non pas 0.
Je vais essayer d'être précis : je souhaite faire un script qui prend un nom de dossier en paramètre (avec le chemin complet) et essaie de lire ce dossier pour savoir combien de fichiers il contient (contenu des sous-dossiers exclu)
si n fichiers dans le dossier : affiche n
si 1 fichier dans le dossier : affiche 1
si le dossier est vide : affiche 0
On attend donc un dossier existant et accessible. Mais si on ne peut pas déterminer le contenu du dossier, soit parce qu’il n'existe pas, qu'on n'a pas les droits, qu'un montage réseau est défaillant, disque défaillant, impossible d'exécuter correctement une commande du script (droits d'exécution sur une commande, saturation mémoire, ...), si on échoue on affiche ERREUR.

Pour illustrer : je faisais un script pour afficher le nombre de fichiers dans un dossier, en utilisant « ls dossier |wc -l » Et je me suis dit, ce serait bien de tester le retour du ls et d'afficher ERREUR si le ls échoue, sinon le wc va afficher 0 dans le cas d'un problème comme par exemple si le dossier est supprimé et n'existe plus, et là ça n'irait pas du tout.

...En écrivant, je viens de penser à cette solution :
var=$(ls bb) && if [ ${#var} -ne 0 ]; then wc -l <<< "$var"; else echo "0"; fi || echo ERREUR

qui fonctionne à tous les coups (elle traite à part le cas du dossier vide).

Je ne sais pas ce que vous pensez de cette solution, si vous avez une meilleure idée, je suis preneur.
Notamment ça ne fonctionne plus si un fichier contient un saut de ligne dans son nom (ls afficher un fichier par ligne et wc va le compter comme 2 fichiers).
Messages postés
1156
Date d'inscription
lundi 2 mai 2016
Statut
Contributeur
Dernière intervention
22 décembre 2020
143 >
Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016

Ok, expliqué comme ça c'est déjà plus clair ;-)

Pour ton problème de saut de ligne (option -Q de ls) :
$ tree cc/
cc/
└── hh\012hh

0 directories, 1 file

$ ls cc/ | wc -l
2

$ ls -Q cc/ | wc -l
1
Messages postés
18240
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
30 novembre 2020
5 209
j'ai presque la même avec test si ls retourne une erreur
$ a=$(ls 2>/dev/null); [[ $? -ne 0 ]] && a=erreur || { [[ ${#a} -eq 0 ]] && a=0 || a=$(wc -l <<<"$a") ; } ; echo $a
Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016
5
Merci à tous, cette solution associée à un ls -Q répond assez bien à mes attentes.
Le seul hic c'est que cela donne une syntaxe plutôt complexe pour un relecteur qui ne serait pas à l'aise avec bash.

Désolé de vous avoir embêté avec mon côté un peu puriste parfois. Mais c'est aussi ça qui m'a poussé à venir poser la question ici.
(D'ailleurs je suis tenté d'en rajouter une couche : pour compter le nombre de dossiers ce n'est pas terrible comme solution, on consomme des ressources pour lister les noms des fichiers alors que c'est totalement inutile, il serait plus performant de seulement incrémenter un compteur pour chaque fichier existant dans le dossier, sans chercher à connaître leur nom, et encore moins à les afficher ou à les enregistrer dans une variable ! Malheureusement je ne sais pas faire cela, je ne sais même pas si c'est possible :/)

Bonne fin de journée :)
Messages postés
1156
Date d'inscription
lundi 2 mai 2016
Statut
Contributeur
Dernière intervention
22 décembre 2020
143 >
Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016

$ tree
.
├── aa
│   ├── fich1
│   ├── fich2
│   └── fich3
├── bb
├── cc
│   └── hh\012hh
└── dd
├── fich
└── script.sed

4 directories, 6 files


L'ensemble des répertoires du répertoire courant :
$ find . 1 -type f  -ls | wc -l
6

Le répertoire contenant 3 fichiers :
$ find aa/ -type f  -ls | wc -l
3

Le répertoire contenant aucun fichier :
$ find bb/ -type f  -ls | wc -l
0

Le répertoire contenant 1 fichier avec saut de ligne dans le nom :
$ find cc/ -type f  -ls | wc -l
1
Messages postés
18240
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
30 novembre 2020
5 209
$ ls
aa bb
$ a=$(ls 2>/dev/null ); [[ $? -ne 0 ]] && a=erreur || a=$(wc -l <<<"$a") ; echo $a
2
$ a=$(ls aa 2>/dev/null ); [[ $? -ne 0 ]] && a=erreur || a=$(wc -l <<<"$a") ; echo $a
1
$ a=$(ls cc 2>/dev/null ); [[ $? -ne 0 ]] && a=erreur || a=$(wc -l <<<"$a") ; echo $a
erreur
Messages postés
111
Date d'inscription
vendredi 6 février 2015
Statut
Membre
Dernière intervention
22 juin 2016
5
Dans le cas d'un dossier qui est vide ça ne marche plus, $a est interprété comme une ligne et le wc -l renvoie 1 au lieu de 0.
j'avais tenté cette approche aussi, le problème vient du fait que quand on enregistre le retour d'une commande dans $a, on perd l'information de savoir s'il y avait ou non un saut de ligne final. :\
(ne marchera pas non plus si un nom de fichier contient un saut de ligne, ce sera considéré comme 2 fichiers)