Tenho um arquivo de texto de vários gigabytes e quero substituir todas as ocorrências de utf8mb4_0900_ai_ci
nele por utf8mb4_unicode_520_ci
.
Normalmente, eu usaria sed -i
para isso como sugerido aqui: encontrar e substituir uma string em um arquivo sem usar o arquivo temporário com SED
No entanto, isso cria um arquivo temporário e preciso que essa substituição ocorra em um ambiente que não tenha espaço em disco para suportar isso.
Como posso modificar o arquivo no local?
Só por diversão, tentei um script bash de substituição no local,
myreplace
. Obviamente, não use isso sem salvar seus dados originais primeiro e fazer testes extensivos. Pode ter problemas com arquivos com mais de 4 GB, embora os números sejam maiores que 32 bits. Além disso, se houver milhões de correspondências,tac
vai usar memória ou espaço de arquivo temporário. Também tive que hackear um pequeno script perl para fazer umseek(2)
, mas já deve haver um em algum lugar.O princípio é usar
grep
para encontrar os deslocamentos de bytes das correspondências, então usartac
para reverter essa lista para que comecemos no final. Abrimos 2 descritores de arquivo no arquivo.fdr
será nossa posição de leitura atual efdw
nossa posição de gravação. Ambos começam no final do arquivo, masfdw
estão no novo final nocional, que está mais adiante pornummatches
timeslen3
, a diferença no comprimento da string de substituição.Usamos a função
domove
para buscar de volta no leitor por uma quantia, buscar de volta no escritor pela mesma quantia, ler e copiar a quantia para o escritor. Então precisamos buscar de volta novamente para nossas novas posições.Buscamos de volta no leitor para pular a string antiga. No escritor buscamos de volta, escrevemos a string de substituição e buscamos de volta sobre ela.
Criei um arquivo de demonstração para testar (
str1
está no script):Meu perl está um pouco enferrujado, mas aqui está o script perl "seek":