Isso funcionará no Bash 4:
ls -l {,**/}*.ext
Para que o glob de asterisco duplo funcione, a globstar
opção precisa ser definida (padrão: ativado):
shopt -s globstar
De man bash
:
globstar
Se definido, o padrão ** usado em uma expansão de nome de arquivo con‐
o texto corresponderá a arquivos e zero ou mais diretórios e
subdiretórios. Se o padrão for seguido por um /, apenas
diretórios e subdiretórios correspondem.
Agora estou me perguntando se pode ter havido um bug no processamento globstar, porque agora usando simplesmente ls **/*.ext
estou obtendo resultados corretos.
Independentemente disso, olhei para a análise que kenorb fez usando o repositório VLC e encontrei alguns problemas com essa análise e em minha resposta imediatamente acima:
As comparações com a saída do find
comando são inválidas, pois a especificação -type f
não inclui outros tipos de arquivo (diretórios em particular) e os ls
comandos listados provavelmente incluem . Além disso, um dos comandos listados,ls -1 {,**/}*.*
- que parece ser baseado no meu acima, só exibe nomes que incluem um ponto para os arquivos que estão em subdiretórios. A pergunta do OP e minha resposta incluem um ponto, pois o que se busca são arquivos com extensão específica.
O mais importante, entretanto, é que há um problema especial ao usar o ls
comando com o padrão globstar **
. Muitas duplicatas surgem, pois o padrão é expandido pelo Bash para todos os nomes de arquivo (e nomes de diretório) na árvore que está sendo examinada. Após a expansão, o ls
comando lista cada deles e seu conteúdo, se forem diretórios.
Exemplo:
Em nosso diretório atual está o subdiretório A
e seu conteúdo:
A
└── AB
└── ABC
├── ABC1
├── ABC2
└── ABCD
└── ABCD1
Nessa árvore, **
expande para "AA / AB A / AB / ABC A / AB / ABC / ABC1 A / AB / ABC / ABC2 A / AB / ABC / ABCD A / AB / ABC / ABCD / ABCD1" (7 entradas) . Se você fizer echo **
isso, será a saída exata que obterá e cada entrada será representada uma vez. No entanto , se você fizer ls **
isso, irá gerar uma lista de cada uma dessas entradas. Basicamente, ele é ls A
seguido por ls A/AB
etc., então A/AB
é mostrado duas vezes. Além disso, ls
separará a saída de cada subdiretório:
...
<blank line>
directory name:
content-item
content-item
Portanto, o uso de wc -l
conta todas aquelas linhas em branco e cabeçalhos de seção de nome de diretório, o que torna a contagem ainda mais difícil.
Este é outro motivo pelo qual você não deve analisarls
.
Como resultado desta análise adicional, recomendo não usar o padrão globstar em qualquer circunstância que não seja iterar sobre uma árvore de arquivos desta maneira:
for entry in **
do
something "$entry"
done
Como comparação final, usei um repositório de origem Bash que tinha à mão e fiz o seguinte:
shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .
Eu costumava tr
mudar os espaços para novas linhas, o que só é válido aqui, já que nenhum nome inclui espaços. Eu costumava sed
remover a liderança ./
de cada linha de saída de find
. Classifiquei a saída de, find
pois normalmente ela não está classificada e a expansão de globs do Bash já está classificada. Como você pode ver, a única saída de diff
foi a .
saída do diretório atual por find
. Quando o fiz, ls ** | wc -l
a saída tinha quase o dobro de linhas.
**/*.ext
. Tem certeza de que funciona para você?