Encontre recursivamente todos os arquivos de diversos formatos de arquivo e procure-os por padrões de nome de arquivo

11

Na melhor das hipóteses, gostaria de receber uma chamada como esta:

$searchtool /path/to/search/ -contained-file-name "*vacation*jpg"

... para que essa ferramenta

  • faz uma varredura recursiva do caminho especificado
  • pega todos os arquivos com formatos de arquivo suportados, que devem ser pelo menos os "mais comuns" como zip, rar, 7z, tar.bz, tar.gz ...
  • e verificar a lista de arquivos do arquivo para o padrão de nome em questão (aqui *vacation*jpg )

Estou ciente de como usar a ferramenta de localização, tar, descompactar e similares. Eu poderia combiná-los com um script de shell, mas estou procurando uma solução simples que pode ser um shell one-liner ou uma ferramenta dedicada (sugestões para ferramentas GUI são bem-vindas, mas minha solução deve ser baseada em linha de comando).

    
por mdo 05.07.2012 / 16:37

6 respostas

9

(Adaptado de Como faço recursivamente grep através de arquivos compactados? )

Instale o AVFS , um sistema de arquivos que fornece acesso transparente dentro dos arquivos. Primeiro, execute este comando uma vez para configurar uma visualização do sistema de arquivos de sua máquina, no qual você pode acessar os arquivos como se fossem diretórios:

mountavfs

Depois disso, se /path/to/archive.zip for um arquivo reconhecido, então ~/.avfs/path/to/archive.zip# é um diretório que parece conter o conteúdo do arquivo.

find ~/.avfs"$PWD" \( -name '*.7z' -o -name '*.zip' -o -name '*.tar.gz' -o -name '*.tgz' \) \
     -exec sh -c '
                  find "$0#" -name "*vacation*.jpg"
                 ' {} 'Test::Version' \;

Explicações:

  • Monte o sistema de arquivos AVFS.
  • Procure por arquivos archive em ~/.avfs$PWD , que é a visualização do AVFS do diretório atual.
  • Para cada arquivo, execute o fragmento de shell especificado (com $0 = nome do arquivo e $1 = padrão a ser pesquisado).
  • $0# é a visualização de diretório do arquivo $0 .
  • {\} em vez de {} é necessário no caso dos argumentos externos find substituírem {} dentro de -exec ; (alguns fazem isso, outros não).

Ou em zsh ≥4.3:

mountavfs
ls -l ~/.avfs$PWD/**/*.(7z|tgz|tar.gz|zip)(e\''
     reply=($REPLY\#/**/*vacation*.jpg(.N))
'\')

Explicações:

  • ~/.avfs$PWD/**/*.(7z|tgz|tar.gz|zip) corresponde a arquivos na visualização do AVFS do diretório atual e de seus subdiretórios.
  • PATTERN(e\''CODE'\') aplica CODE a cada correspondência de PATTERN. O nome do arquivo correspondente está em $REPLY . A configuração da matriz reply transforma a correspondência em uma lista de nomes.
  • $REPLY\# é a visualização de diretório do arquivo.
  • $REPLY\#/**/*vacation*.jpg corresponde a *vacation*.jpg ficheiros no arquivo.
  • O qualificador N glob faz com que o padrão seja expandido para uma lista vazia se não houver correspondência.
por 06.07.2012 / 03:33
9

Se você quer algo mais simples que a solução AVFS, eu escrevi um script Python para fazer isso chamado arkfind . Você pode realmente apenas fazer

$ arkfind /path/to/search/ -g "*vacation*jpg"

Ele fará isso de forma recursiva, para que você possa ver os arquivos dentro de arquivos em uma profundidade arbitrária.

    
por 05.07.2013 / 02:13
2

Minha solução usual :

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|DESIRED_FILE_TO_SEARCH'

Exemplo:

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|characterize.txt'

Resuls são como:

foozip1.zip:
foozip2.zip:
foozip3.zip:
    DESIRED_FILE_TO_SEARCH
foozip4.zip:
...

Se você quiser apenas o arquivo zip com hits :

find -iname '*.zip' -exec unzip -l {} \; 2>/dev/null | grep '\.zip\|FILENAME' | grep -B1 'FILENAME'

FILENAME aqui é usado duas vezes, então você pode usar uma variável.

Com a localização, você pode usar PATH / TO / SEARCH

    
por 05.01.2016 / 21:01
2

Outra solução que funciona é zgrep

zgrep -r filename *.zip
    
por 08.04.2016 / 18:02
2

A facilidade de uso do IMHO também deve ser uma coisa no bash:

 while read -r zip_file ; do echo "$zip_file" ; unzip -l "$zip_file" | \
 grep -i --color=always -R "$to_srch"; \
 done < <(find . \( -name '*.7z' -o -name '*.zip' \)) | \
 less -R

e para tar (este não foi testado ...)

 while read -r tar_file ; do echo "$tar_file" ; tar -tf  "$tar_file" | \
 grep -i --color=always -R "$to_srch"; \
 done < <(find . \( -name '*.tar.gz' -o -name '*.tar' \)) | \
 less -R
    
por 23.09.2016 / 08:28
0

O libarchive do bsdtar pode lidar com a maioria desses formatos de arquivo, então você pode fazer:

find . \( -name '*.zip' -o     \
          -name '*.tar' -o     \
          -name '*.tar.gz' -o  \
          -name '*.tar.bz2' -o \
          -name '*.tar.xz' -o  \
          -name '*.tgz' -o     \
          -name '*.tbz2' -o    \
          -name '*.7z' -o      \
          -name '*.iso' -o     \
          -name '*.cpio' -o    \
          -name '*.a' -o       \
          -name '*.ar' \)      \
       -type f                 \
       -exec bsdtar tf {} '*vacation*jpg' \; 2> /dev/null

Que você pode simplificar (e melhorar para combinar insensitivo a maiúsculas e minúsculas) com o GNU find com:

find . -regextype egrep \
       -iregex '.*\.(zip|7z|iso|cpio|ar?|tar(|\.[gx]z|\.bz2)|tgz|tbz2)' \
       -type f \
       -exec bsdtar tf {} '*vacation*jpg' \; 2> /dev/null

Isso não imprime o caminho do arquivo onde esses arquivos *vacation*jpg são encontrados. Para imprimir esse nome, você pode substituir a última linha por:

-exec sh -ac '
   for ARCHIVE do
     bsdtar tf "$ARCHIVE" "*vacation*jpg" |
       awk '\''{print ENVIRON["ARCHIVE"] ": " $0}'\''
   done' sh {} + 2> /dev/null

que fornece uma saída como:

./a.zip: foo/blah_vacation.jpg
./a.zip: bar/blih_vacation.jpg
./a.tar.gz: foo/blah_vacation.jpg
./a.tar.gz: bar/blih_vacation.jpg

Ou com zsh :

setopt extendedglob # best in ~/.zshrc
for archive (**/*.(#i)(zip|7z|iso|cpio|a|ar|tar(|.gz|.xz|.bz2)|tgz|tbz2)(.ND)) {
  matches=("${(f@)$(bsdtar tf $archive '*vacation*jpg' 2> /dev/null)"})
  (($#matches)) && printf '%s\n' "$archive: "$^matches
}

Observe que há vários outros formatos de arquivo que são apenas zip ou tgz arquivos disfarçados como .jar ou .docx files. Você pode adicioná-los ao seu padrão de pesquisa find / zsh , bsdtar não se importa com a extensão (como, não depende da extensão para determinar o tipo do arquivo).

Observe que *vacation*.jpg acima é correspondido no caminho completo do membro de arquivamento, não apenas no nome do arquivo, portanto, ele corresponderia a vacation.jpg , mas também a vacation/2014/file.jpg .

Para corresponder apenas ao nome do arquivo, um truque seria usar o modo extração , use -s (substituição) que usa regexps com um sinal p para imprimir os nomes dos correspondentes arquivos e, em seguida, verifique se nenhum arquivo é extraído, como:

bsdtar -'s|.*vacation[^/]*$||' -'s|.*||' -xf "$archive"

Observe que ele exibiria a lista em stderr e anexaria >> a cada linha. Em qualquer caso, bsdtar , como a maioria das implementações de tar , pode manejar os nomes dos arquivos em exibição se eles contiverem alguns caracteres como newline ou barra invertida (processados como \n ou \ ).

    
por 23.09.2016 / 09:09

Tags