Substituir string contendo nova linha no arquivo enorme

16

Alguém sabe de uma ferramenta não baseada em linha para pesquisar / substituir sequências "binárias" de uma maneira que consuma pouca memória? Veja esta questão também.

Eu tenho um arquivo de texto de +2 GB que gostaria de processar semelhante ao que isso parece fazer:

sed -e 's/>\n/>/g'

Isso significa que eu quero remover todas as novas linhas que ocorram após > , mas não em nenhum outro lugar, de modo que exclua tr -d .

Esse comando (que recebi de resposta de uma pergunta semelhante ) falha com couldn't re-allocate memory :

sed --unbuffered ':a;N;$!ba;s/>\n/>/g'

Então, existem outros métodos sem recorrer a C? Eu odeio perl, mas estou disposto a fazer uma exceção neste caso: -)

Não sei com certeza nenhum caractere que não ocorra nos dados, portanto, a substituição temporária de \n por outro caractere é algo que eu gostaria de evitar, se possível.

Alguma boa ideia, alguém?

    
por MattBianco 16.06.2014 / 14:23

8 respostas

14

Isso é realmente trivial em Perl, você não deveria odiá-lo!

perl -i.bak -pe 's/>\n/>/' file

Explicação

  • -i : edite o arquivo no lugar e crie um backup do original chamado file.bak . Se você não quiser um backup, use apenas perl -i -pe .
  • -pe : leia o arquivo de entrada linha a linha e imprima cada linha depois de aplicar o script fornecido como -e .
  • s/>\n/>/ : a substituição, assim como sed .

E aqui está uma abordagem awk :

awk  '{if(/>$/){printf "%s",$0}else{print}}' file2 
    
por 16.06.2014 / 14:43
7

Uma solução perl :

$ perl -pe 's/(?<=>)\n//'

Explicação

  • s/// é usado para substituição de string.
  • (?<=>) é o padrão lookbehind.
  • \n corresponde à nova linha.

Os significados do padrão inteiro removendo todas as novas linhas que têm > antes.

    
por 16.06.2014 / 14:30
3

Que tal isso:

sed ':loop
  />$/ { N
    s/\n//
    b loop
  }' file

Para o GNU sed, você também pode tentar adicionar a opção -u ( --unbuffered ) conforme a pergunta. O GNU sed também está feliz com isso como um simples one-liner:

sed ':loop />$/ { N; s/\n//; b loop }' file
    
por 16.06.2014 / 14:41
1

que tal usar o ed?

ed -s test.txt <<< $'/fruits/s/apple/banana/g\nw'

(via link )

    
por 10.10.2014 / 15:48
1

Você deve ser capaz de usar sed com o comando N , mas o truque será excluir uma linha do espaço padrão toda vez que você adicionar outra (para que o espaço padrão contenha apenas 2 linhas consecutivas , em vez de tentar ler o arquivo inteiro) - tente

sed ':a;$!N;s/>\n/>/;P;D;ba'

EDIT: depois de releitura Peter Sedan Famous Sed One- Forros explicados Acredito que uma solução sed melhor seria

sed -e :a -e '/>$/N; s/\n//; ta'

que só acrescenta a seguinte linha no caso de já ter feito uma correspondência > no final, e deve condicionalmente fazer um loop de volta para lidar com o caso de linhas consecutivas correspondentes (é < em> 39. Anexe uma linha à próxima se ela terminar com uma barra invertida "\" exatamente, exceto pela substituição de > por \ como o caractere de junção e pelo fato de o caractere de junção ser retido na saída).

    
por 16.06.2014 / 14:41
1

sed não fornece uma maneira de emitir saída sem uma nova linha final. Sua abordagem usando N funciona fundamentalmente, mas armazena linhas incompletas na memória e, portanto, pode falhar se as linhas ficarem muito longas (as implementações sed não são normalmente projetadas para lidar com linhas extremamente longas).

Você pode usar o awk em vez disso.

awk '{if (/<$/) printf "%s", $0; else print}'

Uma abordagem alternativa é usar tr para trocar o caractere de nova linha por um caractere "chato" e frequente. O espaço pode funcionar aqui - escolha um caractere que tende a aparecer em todas as linhas ou, pelo menos, uma grande proporção de linhas em seus dados.

tr ' \n' '\n ' | sed 's/> />/g' | tr '\n ' ' \n'
    
por 17.06.2014 / 02:49
-1

Existem muitas maneiras de fazer isso, e a maioria aqui é muito boa, mas acho que essa é a minha favorita:

tr '>\n' '\n>' | sed 's/^>*//;H;/./!d;x;y/\n>/>\n/'

Ou até mesmo:

tr '>\n' '\n>' | sed 's/^>*//' | tr '\n>' '>\n'
    
por 16.06.2014 / 20:59