Glob récursif?

80

J'aimerais écrire quelque chose comme ceci:

$ ls **.py

pour obtenir tous les noms de fichiers .py, parcourant de manière récursive une hiérarchie de répertoires.

Même s'il y a des fichiers .py à trouver, le shell (bash) donne cette sortie:

ls: cannot access **.py: No such file or directory

Un moyen de faire ce que je veux?

EDIT: Je tiens à préciser que le cas spécifique de je ne suis pas intéressé ls, mais la question concerne la syntaxe glob.

Paolo
la source

Réponses:

98

Pour faire des globs récursifs dans bash, vous avez besoin de la globstarfonctionnalité de bash version 4 ou supérieure.

De la page de manuel bash:

globstar
    If set, the pattern ** used in a pathname expansion context will
    match all files and zero or more directories and subdirectories.
    If the pattern is followed by a /, only directories and
    subdirectories match.

Pour votre exemple de modèle:

shopt -s globstar
ls **/*.py
Jordan
la source
2
Je recommanderais également l'activationnullglob
Glenn Jackman
6
@glennjackman Mais avant d'activer nullglob, je vous conseillerais vivement de lire les avertissements suivants .
Serge Stroobandt le
2
^ Les avertissements sont passés ici .
usandfriends
1
Avec bash 3.2, ça wc -l {**,.}/*.pymarche très bien
Raphael le
@Raphael J'ai vérifié deux fois les notes de publication et il est clairement indiqué qu'il a été introduit dans la version 4.0. Peut-être que votre distribution a rétroporté un correctif? IIRC RHEL 5 avait rétroporté certaines fonctionnalités. À noter également que 9
semaines se
10
find . -name '*.py'

** ne fait rien de plus qu'un seul *, les deux fonctionnent dans le répertoire courant

doneal24
la source
Intéressant. Bien que je sois plus concentré sur la syntaxe glob en elle-même, car je dois l’utiliser dans un fichier de configuration (directive include). Je n'ai pas besoin d'une liste de fichiers.
Paolo
2
@ Doug O'Neal, ce n'est plus vrai. bash a maintenant copié cette fonctionnalité de zsh (bien qu'elle ait adopté une syntaxe plus proche de celle de ksh93 et ​​que, comme ksh, elle ne supporte pas encore les qualificatifs globbing de zsh, ce qui limite son utilité)
Stéphane Chazelas
Il y a beaucoup de choses que vous pouvez faire avec findsi vous n'avez pas bash 4. Exemples: yourcommand `find . -name '*.py'`(notez les backticks); find . -name '*.py' -exec yourcommand {} \;.
Mars
5

Depuis Bash 4 (y compris zsh), une nouvelle option globbing ( globstar) a été ajoutée pour traiter le modèle **différemment lorsqu’il est défini.

Il correspond au modèle générique et renvoie les noms de fichier et de répertoire correspondants en remplaçant le modèle générique de la commande par les éléments correspondants.

Normalement, lorsque vous utilisez **, cela fonctionne de la même façon *, mais tous les répertoires sont récursifs de manière récursive (comme une boucle).

Pour voir s’il est activé, vérifiez-le par shopt globstar(dans les scripts, utilisez shopt -q globstar).

L'exemple **.pyne fonctionnerait que pour le répertoire en cours, car il ne renvoie pas de liste de répertoires pouvant être récursifs, c'est pourquoi vous devez utiliser plusieurs caractères génériques au niveau du répertoire **/*.pypour qu'il puisse aller plus en profondeur.

S'il vous plaît trouver sur SO peu de tests de syntaxe que j'ai fait pour trouver tous les fichiers de manière récursive.

Kenorb
la source