Glob recursiva?

80

Eu gostaria de escrever algo como isto:

$ ls **.py

para obter todos os nomes de arquivos .py, percorrendo recursivamente uma hierarquia de diretórios.

Mesmo se houver arquivos .py para encontrar, o shell (bash) fornecerá esta saída:

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

Alguma maneira de fazer o que eu quero?

Edição: Gostaria de especificar que não estou interessado no caso específico de ls, mas a pergunta é sobre a sintaxe glob.

Paolo
fonte

Respostas:

98

Para fazer globs recursivos no bash, você precisa do globstarrecurso do bash versão 4 ou superior.

Na página de manual do 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 o seu padrão de exemplo:

shopt -s globstar
ls **/*.py
jordanm
fonte
2
Eu recomendo também permitirnullglob
glenn jackman 4/12
6
@glennjackman Mas antes de ativar nullglob, eu recomendo fortemente a leitura após os avisos .
Serge Stroobandt
2
^ Os avisos foram movidos para aqui .
usandfriends
1
Com o bash 3.2, wc -l {**,.}/*.pyfunciona muito bem
Raphael
@ Rafael Verifiquei as notas de versão e definitivamente diz que foi introduzido na 4.0. Talvez sua distribuição tenha suportado um patch para isso? O IIRC RHEL 5 havia suportado alguns recursos. Também digno de nota, tem sido 9 anos desde o bash 4 foi lançado ...
jordanm
10
find . -name '*.py'

** não faz nada além de um único *, ambos operam no diretório atual

doneal24
fonte
Interessante. No entanto, estou mais focado na sintaxe glob por si só, porque tenho que usá-lo em um arquivo de configuração (incluir diretiva). Não preciso de uma lista de arquivos.
Paolo
2
@ Doug O'Neal, isso não é mais verdade. festa já copiado esse recurso zsh (embora ele adotou uma sintaxe mais próxima à de ksh93 e como ksh, não suporta eliminatórias englobamento do zsh ainda que limita sua utilidade)
Stéphane Chazelas
Você pode fazer muitas coisas findse não tiver o bash 4. Exemplos: yourcommand `find . -name '*.py'`(observe os backticks); find . -name '*.py' -exec yourcommand {} \;.
Mars
5

Desde o Bash 4 (incluindo também o zsh) , foi adicionada uma nova opção de globbing ( globstar), que trata o padrão de maneira **diferente quando está definido.

Ele corresponde ao padrão curinga e retorna os nomes de arquivos e diretórios correspondentes, substituindo o padrão curinga no comando pelos itens correspondentes.

Normalmente, quando você usa **, ele funciona de maneira semelhante a *, mas repete todos os diretórios recursivamente (como um loop).

Para ver se está ativado, verifique-o shopt globstar(em scripts, use shopt -q globstar).

O exemplo **.pyfuncionaria apenas para o diretório atual, pois não retorna uma lista de diretórios que podem ser recorrentes; é por isso que você precisa usar vários curingas no nível de diretório **/*.py, para que possa ir mais fundo.

Por favor em encontrar SO alguns testes de sintaxe que fiz para encontrar todos os arquivos de forma recursiva.

kenorb
fonte