imprima todas as correspondências ou substitua todas as cadeias em um arquivo BIG que NÃO esteja organizado em linha (sem separadores de linha)

2

Os arquivos de 5GB que tenho são fluxos de linhas de dados formados:

    {datarow1...},{datarow2...},...,{datarowN...}

Então, na verdade, podemos dizer que existem linhas {} e até mesmo separadores de linha, mas vêm como uma sequência de três caracteres: },{

Eu quero fazer duas coisas:

  1. imprima " lines " com a string "error" :

    grep -o -P {[^{}]+?error.+?} ES01.log > ES01.err.log
    
  2. torna o arquivo mais "amigável", produzindo explicitamente arquivos com novos separadores de linha

    <ES01.log sed -e 's/},{/}\n{/g' > ESnl01.log
    

Enquanto o acima funciona para arquivos relativamente pequenos (até ~ 100MB), meus arquivos são, infelizmente, muito maiores, portanto, atingindo os problemas de memória aqui:

    grep: memory exhausted
    sed: couldn't re-allocate memory

como grep e sed tentam ler / processar arquivos linha por linha, o que neste caso (sem separadores) leva a carregar arquivos inteiros na memória.

Alguma ideia de como abordar isso usando outro one-liner inteligente?

    
por msciwoj 08.02.2014 / 17:24

4 respostas

2

com gawk :

gawk -v 'RS=},{' '{sub(",", "\n", RT); printf "%s", $0 RT}' < file

equivalente a perl:

perl -pe 'BEGIN{$/="},{"}; s/\,{$/\n{/' < file

Caso contrário, POSIXly:

tr , '\n' < file | awk '{
  if (/^{/ && e) print ""
  printf "%s", $0
  if (/}$/) e=1
  else {e=0; printf ","}}
  END {print ""}'

Envie para grep error os registros com erros e paste -sd, - para restaurar o formato original.

    
por 08.02.2014 / 17:42
1

Você também pode fazer isso em Perl:

perl -ne 'BEGIN{$/="},{"} chomp; 
          s/\n$//; s/^{//; s/}$//; 
          print "{$_}\n"; ' k 

Este é o mesmo princípio que o gawk que o StephaneChazelas sugeriu, em Perl, $/ é o separador de registro, então definimos isso para },{ para ler os registros corretamente e depois imprimi-los com novas linhas.

Você poderia facilmente expandir isso para fazer as duas operações solicitadas:

perl -i -ne 'BEGIN{$/="},{"}
             chomp; 
             s/\n$//; s/^{//; s/}$//; print "{$_}\n"; 
             print STDERR "{$_}\n" if /error/' file 2> ES01.err.log
    
por 08.02.2014 / 18:13
0

Se você estiver disposto a experimentar um programa que provavelmente ainda não está instalado em seu sistema, tente gsar , explicado em esta resposta para o mesmo problema.

gsar é uma pesquisa e (opcionalmente) substitui o utilitário que opera em arquivos binários. No entanto, não pode pesquisar com expressões regulares.

Este comando:

gsar '-s},{' '-r}:x0A{' ES01.log > ESnl01.log

substitui a vírgula entre }{ por um caractere de nova linha, lendo ES01.log e redirecionando a saída para ESnl01.log.

As strings de pesquisa ( -s ) e de substituição ( -r ) não têm o mesmo tamanho.

    
por 17.06.2014 / 14:39
0

Você pode fazer isso simplesmente por meio do Perl usando regex.

perl -pe 's/(?<=}),(?=\{)/\n/g' file
    
por 19.10.2014 / 13:53