Sem memória durante o uso do sed com expressões multilinhas no arquivo gigante

4

No momento, estou tentando remover todas as novas linhas que não são precedidas por um parêntese de fechamento, então criei esta expressão:

sed -r -i -e ":a;N;$!ba;s/([^\)])\n//g;d" reallyBigFile.log

Ele faz o trabalho em arquivos menores, mas neste arquivo grande que estou usando ( 3GB ), ele funciona por um tempo e retorna com um erro de falta de memória:

sed: Couldn't re-allocate memory

Existe alguma maneira de fazer esse trabalho sem me deparar com esse problema. Usando sed em si não é obrigatório, eu só quero fazer isso.

    
por kurast 01.02.2013 / 14:29

2 respostas

3

Seus primeiros três comandos são os culpados:

:a
N
$!ba

Isto lê o arquivo inteiro na memória de uma só vez. O script a seguir deve manter apenas um segmento na memória por vez:

% cat test.sed
#!/usr/bin/sed -nf

# Append this line to the hold space. 
# To avoid an extra newline at the start, replace instead of append.
1h
1!H

# If we find a paren at the end...
/)$/{
    # Bring the hold space into the pattern space
    g
    # Remove the newlines
    s/\n//g 
    # Print what we have
    p
    # Delete the hold space
    s/.*//
    h
}
% cat test.in
a
b
c()
d()
e
fghi
j()
% ./test.sed test.in
abc()
d()
efghij()

Esta solução awk imprimirá cada linha como vem, por isso só terá uma única linha na memória de cada vez:

% awk '/)$/{print;nl=1;next}{printf "%s",$0;nl=0}END{if(!nl)print ""}' test.in
abc()
d()
efghij()
    
por 01.02.2013 / 16:25
1

Para completar, uma solução Perl: perl -p -e '/)$/ || chomp'

Para simetria: -p envolve seu script em uma leitura de loop e impressão linha por linha; o -e expressão / script corresponde a ) no final da linha, se não corresponder (a correspondência é falsa), passa para chomp , o que remove a nova linha no final.

    
por 01.02.2013 / 18:36