Existe-t-il une commande bash qui compte le nombre de fichiers correspondant à un modèle?
Par exemple, je veux obtenir le nombre de tous les fichiers dans un répertoire qui correspondent à ce modèle: log*
Ce simple one-liner devrait fonctionner dans n'importe quel shell, pas seulement bash:
ls -1q log* | wc -l
ls -1q vous donnera une ligne par fichier, même s'ils contiennent des espaces ou des caractères spéciaux tels que des retours à la ligne.
La sortie est dirigée vers wc -l, qui compte le nombre de lignes.
-l
, car cela nécessitestat(2)
sur chaque fichier et aux fins de comptage n'ajoute rien.ls
, car il crée un processus enfant.log*
est étendu par le shell, nonls
, donc un simpleecho
ferait.logs
dans le répertoire en question, alors le contenu de ce répertoire de journaux sera également compté. Ce n'est probablement pas intentionnel.Vous pouvez le faire en toute sécurité (c'est-à-dire que vous ne serez pas bogué par des fichiers avec des espaces ou
\n
dans leur nom) avec bash:Vous devez activer
nullglob
pour ne pas obtenir le littéral*.log
dans le$logfiles
tableau si aucun fichier ne correspond. (Voir Comment «annuler» un 'set -x'? Pour des exemples sur la façon de le réinitialiser en toute sécurité.)la source
shopt -u nullglob
doit être ignorée si ellenullglob
n'a pas été désactivée alors que vous avez commencé.*.log
par just*
comptera les répertoires. Si les fichiers que vous souhaitez énumérer ont la convention de dénomination traditionnelle dename.extension
, utilisez*.*
.Beaucoup de réponses ici, mais certaines ne prennent pas en compte
-l
)*.log
au lieu delog*
logs
qui correspondlog*
)Voici une solution qui les gère tous:
Explication:
-U
provoquels
de ne pas trier les entrées, ce qui signifie qu'il n'a pas besoin de charger la liste complète du répertoire en mémoire-b
imprime les échappements de style C pour les caractères non graphiques, ce qui entraîne de manière cruciale l'impression de nouvelles lignes sous forme de\n
.-a
imprime tous les fichiers, même les fichiers cachés (pas strictement nécessaire lorsque le globlog*
n'implique aucun fichier caché)-d
imprime les répertoires sans essayer de lister le contenu du répertoire, ce quils
serait normalement-1
s'assure qu'il est sur une colonne (ls le fait automatiquement lors de l'écriture dans un tube, donc ce n'est pas strictement nécessaire)2>/dev/null
redirige stderr pour que s'il n'y a aucun fichier journal, ignorez le message d'erreur. (Notez queshopt -s nullglob
cela entraînerait lals
liste de l'ensemble du répertoire de travail à la place.)wc -l
consomme la liste des répertoires au fur et à mesure de sa génération, de sorte que la sortie dels
n'est jamais en mémoire à aucun moment.--
Les noms de fichiers sont séparés de la commande en utilisant--
afin de ne pas être compris comme des arguments dels
(en cas delog*
suppression)La coquille va développer
log*
à la liste complète des fichiers, ce qui peut épuiser la mémoire si elle est un grand nombre de fichiers, donc il est en cours d' exécution à travers grep mieux:Ce dernier gère des répertoires de fichiers extrêmement volumineux sans utiliser beaucoup de mémoire (bien qu'il utilise un sous-shell). Le
-d
n'est plus nécessaire, car il ne répertorie que le contenu du répertoire actuel.la source
Pour une recherche récursive:
wc -c
comptera le nombre de caractères dans la sortie defind
, tandis que-printf x
ditfind
d'imprimer un seulx
pour chaque résultat.Pour une recherche non récursive, procédez comme suit:
la source
-name '*.log'
il comptera tous les fichiers, ce dont j'avais besoin pour mon cas d'utilisation. Le drapeau -maxdepth est également extrêmement utile, merci!find
; imprimez simplement autre chose que le nom du fichier textuel.La réponse acceptée pour cette question est fausse, mais j'ai un faible représentant, je ne peux donc pas y ajouter de commentaire.
La bonne réponse à cette question est donnée par Mat:
Le problème avec la réponse acceptée est que wc -l compte le nombre de caractères de nouvelle ligne, et les compte même s'ils s'impriment sur le terminal sous la forme '?' dans la sortie de 'ls -l'. Cela signifie que la réponse acceptée échoue lorsqu'un nom de fichier contient un caractère de nouvelle ligne. J'ai testé la commande suggérée:
et il signale par erreur une valeur de 2 même s'il n'y a qu'un seul fichier correspondant au modèle dont le nom contient un caractère de nouvelle ligne. Par exemple:
la source
Si vous avez beaucoup de fichiers et que vous ne voulez pas utiliser la
shopt -s nullglob
solution de tableau élégant et bash, vous pouvez utiliser find et ainsi de suite tant que vous n'imprimez pas le nom du fichier (qui peut contenir des nouvelles lignes).Cela trouvera tous les fichiers qui correspondent au journal * et qui ne commencent pas par
.*
- Le "not name. *" Est redondant, mais il est important de noter que la valeur par défaut pour "ls" est de ne pas afficher les fichiers à points, mais la valeur par défaut car trouver, c'est les inclure.C'est une réponse correcte et gère tout type de nom de fichier que vous pouvez lui lancer, car le nom de fichier n'est jamais transmis entre les commandes.
Mais la
shopt nullglob
réponse est la meilleure!la source
find
et l'utilisationls
sont deux façons différentes de résoudre le problème.find
n'est pas toujours présent sur une machine, maisls
est généralement,find
probablement pas toutes ces options sophistiquées pour l'unls
ou l'autre.-maxdepth 1
find
fait cela par défaut. Cela peut créer de la confusion si l'on ne se rend pas compte qu'il existe un dossier enfant caché, et peut rendre son utilisation avantageusels
dans certaines circonstances, ce qui ne signale pas les fichiers cachés par défaut.Voici ma seule doublure pour cela.
la source
set --
ne rien faire d'autre que de nous préparer pour$#
, qui stocke le nombre d'arguments de ligne de commande qui ont été passés au programme shellVous pouvez utiliser l'option -R pour rechercher les fichiers avec ceux à l'intérieur des répertoires récursifs
vous pouvez utiliser des motifs sur le grep
la source
Un commentaire important
(pas assez de réputation pour commenter)
C'est BUGGY :
S'il
shopt -s nullglob
est défini, il imprime le nombre de TOUS les fichiers normaux, pas seulement ceux avec le modèle (testé sur CentOS-8 et Cygwin). Qui sait quels sont les autres bugs insignifiantsls
?C'est CORRECT et beaucoup plus rapide:
Il fait le travail attendu.
Et les temps de fonctionnement diffèrent.
Le 1er:
0.006
sur CentOS, et0.083
sur Cygwin (au cas où il serait utilisé avec précaution).Le 2ème:
0.000
sur CentOS, et0.003
sur Cygwin.la source
Vous pouvez définir une telle commande facilement, en utilisant une fonction shell. Cette méthode ne nécessite aucun programme externe et ne génère aucun processus enfant. Il n'essaye pas d'
ls
analyser les caractères dangereux et gère très bien les caractères «spéciaux» (espaces blancs, nouvelles lignes, barres obliques inverses, etc.). Il ne repose que sur le mécanisme d'extension de nom de fichier fourni par le shell. Il est compatible avec au moins sh, bash et zsh.La ligne ci-dessous définit une fonction appelée
count
qui imprime le nombre d'arguments avec lesquels elle a été appelée.Appelez-le simplement avec le motif souhaité:
Pour que le résultat soit correct lorsque le modèle de globbing n'a pas de correspondance, l'option shell
nullglob
(oufailglob
- qui est le comportement par défaut sur zsh) doit être définie au moment de l'expansion. Il peut être défini comme ceci:En fonction de ce que vous voulez compter, vous pourriez également être intéressé par l'option shell
dotglob
.Malheureusement, avec bash au moins, il n'est pas facile de définir ces options localement. Si vous ne souhaitez pas les définir globalement, la solution la plus simple consiste à utiliser la fonction de cette manière plus compliquée:
Si vous voulez récupérer la syntaxe légère
count log*
, ou si vous voulez vraiment éviter de générer un sous-shell, vous pouvez pirater quelque chose du genre:En prime, cette fonction est d'une utilisation plus générale. Par exemple:
En transformant la fonction en un fichier script (ou un programme C équivalent), appelable depuis le PATH, elle peut également être composée avec des programmes tels que
find
etxargs
:la source
J'ai beaucoup réfléchi à cette réponse, surtout compte tenu des choses à ne pas analyser . Au début, j'ai essayé
qui fonctionnait s'il n'y avait qu'un nom de fichier comme
mais a échoué si j'ai créé un nom de fichier comme celui-ci
J'ai finalement trouvé ce que je mets ci-dessous. Remarque J'essayais d'obtenir un nombre de tous les fichiers dans le répertoire (sans inclure les sous-répertoires). Je le pense, avec les réponses de @Mat et @Dan_Yard, ainsi que d'avoir au moins la plupart des exigences énoncées par @mogsie (je ne suis pas sûr de la mémoire.) Je pense que la réponse de @mogsie est correcte, mais j'essaie toujours de rester à l'écart de l'analyse à
ls
moins que ce ne soit une situation extrêmement spécifique.Plus lisible:
Cela fait une recherche spécifiquement pour les fichiers, délimitant la sortie avec un caractère nul (pour éviter les problèmes d'espaces et de sauts de ligne), puis en comptant le nombre de caractères nuls. Le nombre de fichiers sera un de moins que le nombre de caractères nuls, car il y aura un caractère nul à la fin.
Pour répondre à la question du PO, il y a deux cas à considérer
1) Recherche non récursive:
2) Recherche récursive. Notez que ce qu'il y a à l'intérieur du
-name
paramètre peut devoir être changé pour un comportement légèrement différent (fichiers cachés, etc.).Si quelqu'un souhaite commenter ces réponses par rapport à celles que j'ai mentionnées dans cette réponse, veuillez le faire.
Remarque, je suis arrivé à ce processus de réflexion en obtenant cette réponse .
la source
Voici ce que je fais toujours:
la source
awk 'END{print NR}'
devrait être équivalent àwc -l
.Ce qui signifie lister un fichier par ligne, puis le diriger vers la commande de comptage de mots avec le changement de paramètre pour compter les lignes.
la source
Pour tout compter, dirigez simplement ls vers la ligne de nombre de mots:
Pour compter avec motif, redirigez d'abord vers grep:
la source