Como iterar através de múltiplas extensões de arquivo sem se importar com maiúsculas e minúsculas?

1

Eu vi vários tópicos sobre como iterar através de várias extensões de arquivo, mas na maioria dos casos, a lista está definida.

exemplo:

for file in ${arg}/**/*.{txt,h,py}
do
    ....
done

Como pode ser visto, .TXT arquivos seriam ignorados. E, infelizmente, o cara que respondeu diz que só funciona para o bash4. mas minha configuração usa o bash3.x.

Alguma idéia de como isso pode ser feito?

    
por mrjayviper 23.07.2014 / 06:48

3 respostas

5

Em bash você pode definir nocaseglob :

shopt -s nocaseglob

for file in "$arg"/**/*.{txt,h,py}
do
  ....
done

shopt -u nocaseglob

noclaseglob é bom para usar em qualquer bash desde 2.01, no entanto ** requer bash 4.0 ou posterior (e segue links simbólicos até bash 4.3 onde foi corrigido). Observe a correção para citar $arg , pois haverá problemas se contiverem espaços ou caracteres glob.

Sem usar ** , você pode fazer algo como:

find "$arg" \( -iname '*.txt' -o -iname '*.h' -o -iname '*.py' \) -exec bash -c '
  for file; do
    ...
  done' bash {} +

Isto irá encontrar todos os arquivos que você está procurando e passá-los como argumentos separados para uma nova instância do bash, que então passará por eles. Se a sua operação por arquivo for um único comando, você provavelmente poderá ignorar a nova instância do bash e usar o comando diretamente.

Atualizar

De acordo com os comentários de Stephane abaixo, a solução compatível com POSIX é:

find "$arg" \( -name '*.[tT][xX][tT]' -o -name '*.[hH]' -o -name '*.[pP][yY]' \) \
  -exec sh -c '
  for file do
    ...
  done' sh {} +
    
por 23.07.2014 / 07:30
5

Use zsh :

setopt extendedglob
for f ($arg/**/*.(#i)(txt|h|py)(N.)) {
  ...
}
  • **/ : qualquer nível de subdiretórios
  • (#i) é ativar a correspondência insensível a maiúsculas e minúsculas no resto do glob (como ~(i) in ksh93 ).
  • (N.) é o qualificador glob. N é não retornar um erro se não houver nenhum arquivo correspondente e . para selecionar somente arquivos regulares (o equivalente a find 's -type f )). Você pode adicionar um D lá também para corresponder aos arquivos de ponto (ocultos) e descer para os diretórios ocultos (como find seria o padrão).
por 23.07.2014 / 08:57
1

Que tal um simples:

for file in "$(ls -1 | grep -iE '.txt|.py|.h')";
do
  ....
done

Outra opção simples é

find . -maxdepth 1 -iname '*.txt'; find . -maxdepth 1 -iname '*.py'; find . -maxdepth 1 -iname '*.h'; 

Você pode encontrar os parenteses in () no bash para ter a lista.

    
por 14.08.2017 / 22:22