Substitua o texto rapidamente em um arquivo muito grande

25

Eu tenho um arquivo de texto de 25 GB que precisa de uma string substituída em apenas algumas linhas. Posso usar com sedsucesso, mas leva muito tempo para ser executado.

sed -i 's|old text|new text|g' gigantic_file.sql

Existe uma maneira mais rápida de fazer isso?

eisaacson
fonte
Você conhece os números de linha onde está o texto a substituir? Caso contrário, sua única opção para acelerar é obter um computador mais rápido. O fato de você ter uma grande quantidade de dados significa que levará muito tempo para pesquisá-los.
David King
Eu posso grep para os números de linha muito rapidamente, então sim.
eisaacson
Você também pode usar vários núcleos de CPU para acelerá-lo - rankfocus.com/use-cpu-cores-linux-commands
ahaswer
Não use sed para arquivos grandes. Dê uma olhada no vi ou no vim .
MikeJRamsey56 26/02

Respostas:

26

Podes tentar:

sed -i '/old text/ s//new text/g' gigantic_file.sql

Desta referência :

OTIMIZANDO PARA A VELOCIDADE: Se for necessário aumentar a velocidade de execução (devido a grandes arquivos de entrada ou processadores lentos ou discos rígidos), a substituição será executada mais rapidamente se a expressão "localizar" for especificada antes de fornecer "s /.../. ../ "instrução.

Aqui está uma comparação sobre um arquivo 10G. Antes:

$ time sed -i 's/original/ketan/g' wiki10gb
real    5m14.823s
user    1m42.732s
sys     1m51.123s

Depois de:

$ time sed -i '/ketan/ s//original/g' wiki10gb
real    4m33.141s
user    1m20.940s
sys     1m44.451s
mkc
fonte
O último sedestá incorreto. Eu editei este post ontem para corrigir o último sedcomando que deveria ser time sed -i '/original/ s//ketan/g' wiki10gbe não time sed -i '/ketan/ s//original/g' wiki10gb. Estou revertendo minha edição hoje porque 1. os horários não correspondem mais ao comando e 2. Fiz o mesmo teste com o GNU sed em um arquivo de 3 GB ou mais e não observo nenhuma diferença entre as duas sedalternativas. Suspeito que a diferença nos tempos se deva ao erro de ortografia.
xhienne
@xhienne Não sei ao certo o que você quer dizer com erro de ortografia. Na primeira execução, estou substituindo a palavra 'original' por 'cetana' e na segunda substituindo o termo 'cetana' pelo termo 'original', resultando em igual número de substituições em ambos os casos.
Mkc 24/03/19
1
Eu estava aplicando uma "correção" relatada por um novo usuário com reputação insuficiente. Agora eu entendo o que você fez. No entanto, se você quiser provar que uma sintaxe é melhor que a outra, é necessário fazer exatamente a mesma operação que não é o caso aqui (em termos de CPU, procurar uma sequência de 5 caracteres não é o mesmo que procurar uma Sequência de 7 caracteres). Além disso, esse tipo de teste em um arquivo de 10 GB depende muito da carga da sua máquina (CPU, disco). Eu vi muitas flutuações nos timeresultados pessoalmente, mas, no geral, não houve diferença no tempo.
xhienne
Acredito que isso esteja relacionado - veja a resposta aceita aqui, stackoverflow.com/questions/11145270/… >> sed transmite o arquivo inteiro, mas, como observado nesta resposta, especificar o número da linha (se conhecido) ajuda: no meu caso , um aumento de aproximadamente 2 vezes na velocidade de execução (GNU sed 4.5). Você pode grep -n ou ripgrep (rg) para encontrar números de linhas, com base em pesquisas de padrões. Com efeito, especificar o número da linha é como ter um resultado de pesquisa nesse arquivo, conforme a resposta acima.
Victoria Stuart
1

A resposta curta é "Não" - seu fator limitante nesse tipo de operação é a E / S do disco. Não há como transmitir 25 GB de disco mais rapidamente. Você pode obter uma pequena melhoria se não editar o local e gravar o resultado da sedunidade em uma unidade separada (se houver uma disponível) - porque dessa maneira você pode ler de uma, enquanto escreve para outra e há um pouco menos contenção como resultado.

Você pode acelerar um pouco não usando o mecanismo de expressão regular para cada linha - por exemplo, usando perl (tenho certeza de que você pode fazer isso com sedmas não conheço a sintaxe) - isso começará a partir de linha 10.000 em diante.

perl -pe '$. > 10_000 && s/old_text/new_text/g' 

E se houver algum tipo de complicação nos ER (metacaracteres), minimizá-los melhorará um pouco a eficiência do mecanismo regex.

Sobrique
fonte
1
Em sed que seriased -i '10000,$ s/old_text/new_text/g'
Dani_l
Encantador. Não sei como se sedcompara - presumo um pouco mais rápido, mas não muito por causa do tamanho do arquivo.
Sobrique
Eu diria que o perl é mais rápido que o sed, mas o sed é um pouco menos enigmático ou exige menos de uma curva de aprendizado inicial.
Dani_l
1
Veja, agora eu teria dito o oposto - você pode (quase) de gravação sedem perl, mas este último também permite que você escreva mais detalhado roteiros também.
Sobrique
0

Se os textos novos e antigos tiverem o mesmo comprimento, você poderá procurar no arquivo e gravar apenas os bytes alterados, em vez de copiar o arquivo inteiro. Caso contrário, você ficará preso à movimentação de muitos dados.

Nota: isso é complicado e envolve escrever código personalizado.

Consulte a página de manual do fseek, se você estiver trabalhando em C ou C ++, ou seus wrappers de idiomas favoritos para as chamadas de sistema de busca e gravação.

Se você insistir em usar apenas a linha de comando e conseguir os desvios de bytes do texto, poderá escrever o texto de substituição no lugar com comandos "dd" escritos com cuidado.

stolenmoment
fonte