Qu'est-ce qui s'étend récursivement à tous les fichiers du répertoire actuel?
91
Je sais qu'il **/*.exts'étend à tous les fichiers de tous les sous-répertoires correspondants *.ext, mais qu'est-ce qu'une extension similaire qui inclut également tous ces fichiers dans le répertoire actuel ?
Ma fête ne gère pas **/*.ext. Êtes-vous sûr que cela fonctionne pour vous?
tangens
@tangens Vous devez activer l' globstaroption selon la réponse de Dennis.
kenorb
Réponses:
110
Cela fonctionnera dans Bash 4:
ls -l {,**/}*.ext
Pour que le glob double astérisque fonctionne, l' globstaroption doit être définie (par défaut: activé):
shopt -s globstar
De man bash:
globstar
S'il est défini, le modèle ** utilisé dans une extension de nom de fichier
le texte correspondra à un fichier et à zéro ou plusieurs répertoires et
sous-répertoires. Si le motif est suivi d'un /, seulement
les répertoires et les sous-répertoires correspondent.
Maintenant, je me demande s'il peut y avoir eu un bogue dans le traitement de globstar, car maintenant, en utilisant simplement, j'obtiens des ls **/*.extrésultats corrects.
Quoi qu'il en soit, j'ai regardé l' analyse kenorb en utilisant le référentiel VLC et trouvé des problèmes avec cette analyse et dans ma réponse immédiatement ci-dessus:
Les comparaisons avec la sortie de la findcommande ne sont pas valides car la spécification -type fn'inclut pas d'autres types de fichiers (répertoires en particulier) et les lscommandes listées le font probablement. De plus, l'une des commandes répertoriées, ls -1 {,**/}*.*- qui semble être basée sur la mienne ci-dessus, ne renvoie que les noms qui incluent un point pour les fichiers qui se trouvent dans des sous-répertoires. La question de l'OP et ma réponse comportent un point puisque ce qui est recherché, ce sont des fichiers avec une extension spécifique.
Le plus important, cependant, est qu'il y a un problème spécial lors de l'utilisation de la lscommande avec le modèle globstar **. De nombreux doublons surviennent car le modèle est étendu par Bash à tous les noms de fichiers (et noms de répertoires) dans l'arborescence examinée. Suite à l'expansion, la lscommande répertorie chacun d'entre eux et leur contenu s'il s'agit de répertoires.
Exemple:
Dans notre répertoire actuel se trouve le sous-répertoire Aet son contenu:
A
└── AB
└── ABC
├── ABC1
├── ABC2
└── ABCD
└── ABCD1
Dans cet arbre, se **développe en "AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1" (7 entrées) . Si vous le faites, echo **c'est la sortie exacte que vous obtiendrez et chaque entrée est représentée une fois. Cependant , si vous le faites, ls **il affichera une liste de chacune de ces entrées. Donc, essentiellement, il est ls Asuivi de ls A/AB, etc., donc il A/ABest montré deux fois. De plus, lsva séparer la sortie de chaque sous-répertoire:
Donc, utiliser wc -lcompte toutes ces lignes vides et ces en-têtes de section de nom de répertoire, ce qui jette le décompte encore plus loin.
C'est une autre raison pour laquelle vous ne devriez pas analyserls .
À la suite de cette analyse plus approfondie, je recommande de ne pas utiliser le modèle globstar dans des circonstances autres que l'itération sur une arborescence de fichiers de cette manière:
for entry in**do
something "$entry"done
En guise de comparaison finale, j'ai utilisé un référentiel de sources Bash que j'avais sous la main et j'ai fait ceci:
J'avais l'habitude trde changer les espaces en nouvelles lignes, ce qui n'est valable qu'ici car aucun nom n'inclut d'espace. J'avais l'habitude sedde supprimer le début ./de chaque ligne de sortie find. J'ai trié la sortie findcar elle n'est normalement pas triée et l'expansion des globs de Bash est déjà triée. Comme vous pouvez le voir, la seule sortie de diffétait la .sortie du répertoire courant par find. Quand j'ai fait ls ** | wc -lla sortie avait presque deux fois plus de lignes.
J'ai testé Ubuntu et Cygwin, et globstarest par défautoff
Steven Penny
12
La meilleure réponse! mais je pense que cela **/*.extdevrait suffire. De plus, vous n'aurez pas les fichiers cachés sauf si vous shopt -s dotglob.
gniourf_gniourf
2
Pour désactiver globstar: shopt -u globstar.
kenorb
4
@gniourf_gniourf La question demande en fait d'inclure le répertoire actuel spécifiquement donc non, **/*.extne suffira pas
msciwoj
2
@dotnetCarpenter: La version de Bash livrée avec MacOS est la 3.2 qui ne prend pas en charge globstar, comme vous l'avez découvert. Un double astérisque est traité de la même manière qu'un simple. Globstar a été introduit dans Bash 4.0.
Suspendu jusqu'à nouvel ordre.
13
Cela affichera tous les fichiers du répertoire courant et de ses sous-répertoires qui se terminent par «.ext».
Bien que cette réponse ne réponde pas à «l'expansion» demandée par le PO au sens strict, elle est plus susceptible de produire le résultat souhaité.
Suspendu jusqu'à nouvel ordre.
7
Vous pouvez utiliser: **/*.*pour inclure tous les fichiers de manière récursive (activer par:) shopt -s globstar.
Veuillez trouver ci-dessous des tests sur d'autres variantes et leur comportement.
Dossier de test avec 3472 fichiers dans l'exemple de dossier du référentiel VLC :
(Fichiers total de 3472 comptés comme par: find . -type f | wc -l)
ls -1 **/*.* - renvoie 3338
ls -1 {,**/}*.*- renvoie 3341 (comme proposé par Dennis )
ls -1 {,**/}* - renvoie 8265
ls -1 **/*- renvoie 7817, sauf les fichiers cachés (comme proposé par Dennis )
ls -1 **/{.[^.],}*- renvoie 7869 (comme proposé par Dennis )
ls -1 {,**/}.?* - renvoie 15855
ls -1 {,**/}.* - renvoie 20321
Je pense donc que la méthode la plus proche pour lister tous les fichiers de manière récursive est le premier exemple ( **/*.*) selon le commentaire gniourf-gniourf (en supposant que les fichiers ont les extensions appropriées, ou utilisent celle spécifique), car le deuxième exemple donne quelques doublons supplémentaires comme ci-dessous :
Pour inclure les fichiers cachés, utilisez: shopt -s dotglob(désactiver par shopt -u dotglob). Ce n'est pas recommandé, car cela peut affecter des commandes telles que mvou rmet vous pouvez supprimer accidentellement les mauvais fichiers.
Sur le terminal Mac et bash avec globstar activé, j'ai trouvé la solution ci-dessus ( **/*.*) informative et fonctionnait mieux. La réponse acceptée a provoqué des doublons d'éléments dans le répertoire supérieur. Mon modèle de travail était:"${path}"**/*.*
mummybot
Il serait intéressant d'essayer ceci avec d'autres options comme nullglob et dotglob
Wilf
3
$ find .-type f
Cela listera tous les fichiers du répertoire actuel. Vous pouvez ensuite exécuter une autre commande sur la sortie en utilisant -exec
$find .-type f -exec grep "foo"{} \;
Cela grepera chaque fichier de la recherche pour la chaîne "foo".
Maintenant que c'est 11 ans plus tard, il est peut-être temps que quelqu'un souligne que cela find . -type fs'applique de manière récursive avec la racine du répertoire courant, pas seulement au répertoire courant.
Roger Dahl
3
Pourquoi ne pas simplement utiliser l'extension d'accolades pour inclure également le répertoire actuel?
./{*,**/*}.ext
L'expansion de l'accolade se produit avant l'expansion de glob, vous pouvez donc faire ce que vous voulez avec les anciennes versions de bash, et pouvez renoncer au singe avec globstar dans les versions plus récentes.
En outre, il est considéré comme une bonne pratique dans bash d'inclure le leader ./dans vos modèles glob.
**/*.ext
. Êtes-vous sûr que cela fonctionne pour vous?globstar
option selon la réponse de Dennis.Réponses:
Cela fonctionnera dans Bash 4:
Pour que le glob double astérisque fonctionne, l'
globstar
option doit être définie (par défaut: activé):De
man bash
:Maintenant, je me demande s'il peut y avoir eu un bogue dans le traitement de globstar, car maintenant, en utilisant simplement, j'obtiens des
ls **/*.ext
résultats corrects.Quoi qu'il en soit, j'ai regardé l' analyse kenorb en utilisant le référentiel VLC et trouvé des problèmes avec cette analyse et dans ma réponse immédiatement ci-dessus:
Les comparaisons avec la sortie de la
find
commande ne sont pas valides car la spécification-type f
n'inclut pas d'autres types de fichiers (répertoires en particulier) et lesls
commandes listées le font probablement. De plus, l'une des commandes répertoriées,ls -1 {,**/}*.*
- qui semble être basée sur la mienne ci-dessus, ne renvoie que les noms qui incluent un point pour les fichiers qui se trouvent dans des sous-répertoires. La question de l'OP et ma réponse comportent un point puisque ce qui est recherché, ce sont des fichiers avec une extension spécifique.Le plus important, cependant, est qu'il y a un problème spécial lors de l'utilisation de la
ls
commande avec le modèle globstar**
. De nombreux doublons surviennent car le modèle est étendu par Bash à tous les noms de fichiers (et noms de répertoires) dans l'arborescence examinée. Suite à l'expansion, lals
commande répertorie chacun d'entre eux et leur contenu s'il s'agit de répertoires.Exemple:
Dans notre répertoire actuel se trouve le sous-répertoire
A
et son contenu:Dans cet arbre, se
**
développe en "AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1" (7 entrées) . Si vous le faites,echo **
c'est la sortie exacte que vous obtiendrez et chaque entrée est représentée une fois. Cependant , si vous le faites,ls **
il affichera une liste de chacune de ces entrées. Donc, essentiellement, il estls A
suivi dels A/AB
, etc., donc ilA/AB
est montré deux fois. De plus,ls
va séparer la sortie de chaque sous-répertoire:Donc, utiliser
wc -l
compte toutes ces lignes vides et ces en-têtes de section de nom de répertoire, ce qui jette le décompte encore plus loin.C'est une autre raison pour laquelle vous ne devriez pas analyser
ls
.À la suite de cette analyse plus approfondie, je recommande de ne pas utiliser le modèle globstar dans des circonstances autres que l'itération sur une arborescence de fichiers de cette manière:
En guise de comparaison finale, j'ai utilisé un référentiel de sources Bash que j'avais sous la main et j'ai fait ceci:
J'avais l'habitude
tr
de changer les espaces en nouvelles lignes, ce qui n'est valable qu'ici car aucun nom n'inclut d'espace. J'avais l'habitudesed
de supprimer le début./
de chaque ligne de sortiefind
. J'ai trié la sortiefind
car elle n'est normalement pas triée et l'expansion des globs de Bash est déjà triée. Comme vous pouvez le voir, la seule sortie dediff
était la.
sortie du répertoire courant parfind
. Quand j'ai faitls ** | wc -l
la sortie avait presque deux fois plus de lignes.la source
globstar
est par défautoff
**/*.ext
devrait suffire. De plus, vous n'aurez pas les fichiers cachés sauf si vousshopt -s dotglob
.globstar
:shopt -u globstar
.**/*.ext
ne suffira pasCela affichera tous les fichiers du répertoire courant et de ses sous-répertoires qui se terminent par «.ext».
la source
Vous pouvez utiliser:
**/*.*
pour inclure tous les fichiers de manière récursive (activer par:)shopt -s globstar
.Veuillez trouver ci-dessous des tests sur d'autres variantes et leur comportement.
Dossier de test avec 3472 fichiers dans l'exemple de dossier du référentiel VLC :
(Fichiers total de 3472 comptés comme par:
find . -type f | wc -l
)ls -1 **/*.*
- renvoie 3338ls -1 {,**/}*.*
- renvoie 3341 (comme proposé par Dennis )ls -1 {,**/}*
- renvoie 8265ls -1 **/*
- renvoie 7817, sauf les fichiers cachés (comme proposé par Dennis )ls -1 **/{.[^.],}*
- renvoie 7869 (comme proposé par Dennis )ls -1 {,**/}.?*
- renvoie 15855ls -1 {,**/}.*
- renvoie 20321Je pense donc que la méthode la plus proche pour lister tous les fichiers de manière récursive est le premier exemple (
**/*.*
) selon le commentaire gniourf-gniourf (en supposant que les fichiers ont les extensions appropriées, ou utilisent celle spécifique), car le deuxième exemple donne quelques doublons supplémentaires comme ci-dessous :et l'autre génère encore plus de doublons.
Pour inclure les fichiers cachés, utilisez:
shopt -s dotglob
(désactiver parshopt -u dotglob
). Ce n'est pas recommandé, car cela peut affecter des commandes telles quemv
ourm
et vous pouvez supprimer accidentellement les mauvais fichiers.la source
**/*.*
) informative et fonctionnait mieux. La réponse acceptée a provoqué des doublons d'éléments dans le répertoire supérieur. Mon modèle de travail était:"${path}"**/*.*
Cela listera tous les fichiers du répertoire actuel. Vous pouvez ensuite exécuter une autre commande sur la sortie en utilisant -exec
Cela grepera chaque fichier de la recherche pour la chaîne "foo".
la source
find . -type f
s'applique de manière récursive avec la racine du répertoire courant, pas seulement au répertoire courant.Pourquoi ne pas simplement utiliser l'extension d'accolades pour inclure également le répertoire actuel?
L'expansion de l'accolade se produit avant l'expansion de glob, vous pouvez donc faire ce que vous voulez avec les anciennes versions de bash, et pouvez renoncer au singe avec globstar dans les versions plus récentes.
En outre, il est considéré comme une bonne pratique dans bash d'inclure le leader
./
dans vos modèles glob.la source