¿Globo recursivo?

80

Me gustaría escribir algo como esto:

$ ls **.py

para obtener todos los nombres de archivo .py, recorriendo recursivamente una jerarquía de directorios.

Incluso si hay archivos .py para encontrar, el shell (bash) da este resultado:

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

¿Alguna forma de hacer lo que quiero?

EDITAR: Me gustaría especificar que no estoy interesado en el caso específico de ls, pero la pregunta es sobre la sintaxis global.

Paolo
fuente

Respuestas:

98

Para hacer globs recursivos en bash, necesitas la globstarfunción de bash versión 4 o superior.

De la página de manual de 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.

Para su patrón de ejemplo:

shopt -s globstar
ls **/*.py
jordanm
fuente
2
También recomendaría habilitarlonullglob
glenn jackman
66
@glennjackman Pero antes de habilitar nullglob, recomiendo leer las siguientes advertencias .
Serge Stroobandt
2
^ Las advertencias se han mudado aquí .
usandfriends
1
Con bash 3.2, wc -l {**,.}/*.pyfunciona bien
Raphael
@Raphael Revisé dos veces las notas de la versión y definitivamente dice que se introdujo en 4.0. ¿Quizás su distribución ha respaldado un parche? IIRC RHEL 5 había soportado algunas características. También es de destacar que han pasado 9 años desde que se lanzó bash 4 ...
jordanm
10
find . -name '*.py'

** no hace más que un solo *, ambos operan en el directorio actual

doneal24
fuente
Interesante. Sin embargo, estoy más centrado en la sintaxis global, porque tengo que usarla en un archivo de configuración (directiva de inclusión). No necesito una lista de archivos.
Paolo
2
@ Douglas O'Neal, eso ya no es cierto. bash ahora ha copiado esa función zsh (aunque adoptó una sintaxis más cercana a la de ksh93 y, al igual que ksh, aún no admite los calificadores de zsh que limitan su utilidad)
Stéphane Chazelas
Hay muchas cosas que puede hacer findsi no tiene bash 4. Ejemplos: yourcommand `find . -name '*.py'`(tenga en cuenta los backticks); find . -name '*.py' -exec yourcommand {} \;.
Marte
5

Desde Bash 4 (que también incluye zsh) se ha agregado una nueva opción global ( globstar) que trata el patrón de manera **diferente cuando se configura.

Está haciendo coincidir el patrón comodín y devolviendo los nombres de archivo y directorio que coinciden reemplazando el patrón comodín en el comando con los elementos coincidentes.

Normalmente, cuando lo usa **, funciona de manera similar *, pero recurre a todos los directorios de forma recursiva (como un bucle).

Para ver si está habilitado, verifíquelo mediante shopt globstar(en scripting, use shopt -q globstar).

El ejemplo **.pyfuncionaría solo para el directorio actual, ya que no devuelve una lista de directorios que pueden ser recurrentes, por lo que es necesario usar comodines de nivel de directorio múltiple **/*.py, para que pueda profundizar.

Busque en SO pocas pruebas de sintaxis que hice para encontrar todos los archivos de forma recursiva.

kenorb
fuente