Bash: Encontre a pasta contendo dois arquivos

3

Hy, Eu tenho uma grande árvore de diretórios. Eu quero descobrir todos os diretórios que contêm um arquivo, cujo nome termina com ".ext1" e um arquivo cujo nome termina com ".ext2".

Como isso é possível? Pensei em usar dois achados, um para ".ext1" e outro para ".ext2", mas preciso encontrar a interseção, como isso pode ser feito?

Obrigado!

    
por theomega 15.09.2010 / 14:29

4 respostas

5

Aqui está uma solução relativamente simples que executa find apenas uma vez, armazena sua saída em um arquivo temporário e, em seguida, divide e agrupa os resultados para as duas extensões.

tmp=$(mktemp)
find . -name '*.ext1' -o -name '*.ext2' | sort >"$tmp"
comm -12 <(<tmp sed -n 's!/[^/]*\.ext1$!!p' | sort) \
         <(<tmp sed -n 's!/[^/]*\.ext2$!!p' | sort)
rm "$tmp"

Outro método é executar find para iterar nos diretórios e usa um programa auxiliar para verificar se um padrão tem correspondências. Note que a verificação de existência funciona neste caso, mas você precisa de algo mais complicado se o padrão de pesquisa não corresponder a si mesmo e for um possível nome de arquivo.

find . -type d -exec sh -c '{ set "$0"/*.ext1; [ -e "$1" ]; } &&
                            { set "$0"/*.ext2; [ -e "$1" ]; }' {} \;

Aqui está uma solução zsh que opera como este último comando:

echo **/*(/e\''set -- $REPLY/*.ext1(N[1]) $REPLY/*.ext2(N[1]); ((#==2))'\')

Aqui está outra solução zsh que procura *.ext1 e seleciona apenas os diretórios que também têm *.ext2 :

echo ./**/*.ext1(e\''REPLY=${REPLY:h}; set -- $REPLY/*.ext2(N); ((#))'\')

Aqui está uma solução Perl parcial; Devido às vicissitudes do globbing de Perl, ele não funcionará se os nomes dos diretórios contiverem espaços (existem maneiras de corrigir isso, mas não consigo encontrar um que seja remotamente elegante).

perl -l -MFile::Find -e \
  'find {no_chdir => 1,
         wanted => sub {<$_/*.ext1> and <$_/*.ext2> and print}}, "."'
    
por 15.09.2010 / 22:19
2

Se você souber o nome exato de cada arquivo:

find start_dir -type d -exec test -e {}/file.ext1 -a -e {}/file.ext2 \; -print

O hack excepcionalmente feio funcionará se tudo o que você sabe são as extensões:

find start_dir -type d -execdir bash -c 'shopt -s nullglob; eval '\''test -n "$(echo '{}'/*.ext1)" -a -n "$(echo '{}'/*.ext2)"'\''' \; -print

Também pode ser muito lento se você tiver muitos diretórios para pesquisar.

    
por 15.09.2010 / 16:26
1

Se for executado a partir da cabeça da árvore de diretórios, isso parece funcionar

find $(find . -name "*.ext1" -printf %h\n) -name "*.ext2" -printf %h\n
    
por 15.09.2010 / 16:34
0

deve ser uma solução melhor, mas:

find -type d | while read i ; do [ 'ls "$i" -1 | grep -oe '.ext1$\|.ext2$' | sort -u | wc -l' = 2 ] && echo $i ; done
    
por 15.09.2010 / 16:13

Tags