Como posso catar o conteúdo dos arquivos encontrados usando o find em um único arquivo?

9

Consegui me filmar onde dói (muito ruim) reformatando uma partição que continha dados valiosos. Claro que não foi intencional, mas aconteceu.

No entanto, consegui usar testdisk e photorec para recuperar a maioria dos dados. Então agora eu tenho todos esses dados distribuídos em quase 25.000 diretórios. A maioria dos arquivos são arquivos .txt, enquanto o restante são arquivos de imagem. Existem mais de 300 arquivos .txt em cada diretório.

Eu posso grep ou usar find para extrair determinadas seqüências de caracteres dos arquivos .txt e enviá-las para um arquivo. Por exemplo, aqui está uma linha que usei para verificar se meus dados estão nos arquivos recuperados:

find ./recup*/ -name '*.txt' -print | xargs grep -i "searchPattern"

Eu posso enviar "searchPattern" para um arquivo, mas isso me dá esse padrão. Aqui está o que eu realmente gostaria de realizar:

Percorra todos os arquivos e procure por uma string específica. Se essa string for encontrada em um arquivo, coloque TODO o conteúdo desse arquivo em um arquivo de saída. Se o padrão for encontrado em mais de um arquivo, acrescente o conteúdo dos arquivos subseqüentes ao arquivo de saída. Note que eu simplesmente não quero produzir o padrão que estou procurando, mas TODO o conteúdo do arquivo no qual os padrões são encontrados.

Eu acho que isso é factível, mas eu não sei como pegar todo o conteúdo de um arquivo depois de usar um padrão específico dele.

    
por Ami 12.09.2014 / 02:15

4 respostas

8

Se eu entendi sua meta corretamente, o seguinte fará o que você deseja:

find ./recup*/ -name '*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

Isso procurará todos os arquivos *.txt em ./recup*/ , teste cada um por searchPattern , se corresponder a cat do arquivo. A saída de todos os arquivos cat ed será direcionada para outputfile.txt .

Repita para cada padrão e arquivo de saída.

Se você tiver um número muito grande de diretórios correspondentes a ./recup* , poderá acabar com argument list too long error . A maneira simples de contornar isso é fazer algo assim:

find ./ -mindepth 2 -path './recup*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

Isto irá corresponder ao caminho completo. Então, ./recup01234/foo/bar.txt será correspondido. O -mindepth 2 é para que não corresponda a ./recup.txt ou ./recup0.txt .

    
por 12.09.2014 / 02:29
3

Em vez de gerar seu padrão, imprima o nome do arquivo usando "-l" no grep e use-o como entrada para cat.

find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern" | xargs cat

ou

cat $( find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern")

Suspeito que você possa preencher os detalhes restantes. BTW, se você pode ter espaços ou outros caracteres estranhos nos nomes de arquivos (improvável neste caso específico, mas para propósitos futuros), use -print0 no find e -Z no grep, combinado com a opção -0 no xargs para usar Bytes nulos entre nomes de arquivos, em vez de novas linhas.

find ./recup*/ -name '*.txt' -print0 | xargs -0 grep -Zli "searchPattern" | xargs -0 cat
    
por 12.09.2014 / 04:36
1

Este não é exatamente o código ideal, mas é muito simples e funciona bem se a eficiência não for um problema. O problema é que ele percorre os arquivos várias vezes, mesmo que a string já tenha sido encontrada neles.

Primeiramente, pesquise suas strings e grave os arquivos correspondentes em uma lista.

find ./recup*/ -name '*.txt' -execdir grep -il "searchPattern" {} >> /tmp/file_list \;

Repita esta etapa substituindo searchPattern conforme necessário. Isso produz uma lista de arquivos correspondentes em /tmp/file_list .

O problema é que esse arquivo pode ter duplicatas nele. Portanto, podemos substituir as duplicatas com |sort|uniq . A parte sort coloca as duplicatas adjacentes umas às outras, para que uniq possa removê-las. Em seguida, você pode cat desses arquivos juntos usando xargs (com cada nome de arquivo separado por nova linha \n ). Portanto,

</tmp/file_list sort | uniq | xargs -d "\n" cat > final_file.txt

Diferentemente das outras respostas, isso tem duas etapas e um arquivo temporário. Por isso, só recomendo se você tiver vários padrões para encontrar.

    
por 12.09.2014 / 03:51
0

Dependendo do seu shell e ambiente, você poderia algo assim (no bash)

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1\|searchPattern2\|searchPattern3' "$file"; then
    cat "$file" >> some/other/file
  fi
done < <(find ./recup*/ -name '*.txt' -print0)

Se você quiser separar os resultados de acordo com o padrão, modifique isso para algo como

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1' "$file"; then
    cat "$file" >> some/other/file1
  elif grep -qim1 'searchPattern2' "$file"; then
    cat "$file" >> some/other/file2
  elif grep -qim1 'searchPattern3' "$file"; then
    cat "$file" >> some/other/file3
  fi
done < <(find ./recup*/ -name '*.txt' -print0)
    
por 12.09.2014 / 03:45