Reemplazar texto rápidamente en un archivo muy grande

25

Tengo un archivo de texto de 25 GB que necesita reemplazar una cadena en solo unas pocas líneas. Puedo usarlo con sedéxito, pero lleva mucho tiempo ejecutarlo.

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

¿Hay una manera más rápida de hacer esto?

eisaacson
fuente
¿Conoces los números de línea donde está el texto a reemplazar? Si no, su única opción para acelerarlo es obtener una computadora más rápida. El hecho de que tenga una gran cantidad de datos significa que tomará una gran cantidad de tiempo buscarlos.
David King
Puedo buscar los números de línea bastante rápido, así que sí.
eisaacson
También puede usar múltiples núcleos de CPU para acelerarlo - rankfocus.com/use-cpu-cores-linux-commands
ahaswer
No use sed para archivos grandes. Echa un vistazo a vi o vim en su lugar.
MikeJRamsey56

Respuestas:

26

Puedes probar:

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

De esta referencia :

OPTIMIZAR LA VELOCIDAD: si la velocidad de ejecución necesita ser aumentada (debido a archivos de entrada grandes o procesadores lentos o discos duros), la sustitución se ejecutará más rápidamente si se especifica la expresión "buscar" antes de dar "s /.../. ../" instrucción.

Aquí hay una comparación sobre un archivo 10G. Antes de:

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

Después:

$ time sed -i '/ketan/ s//original/g' wiki10gb
real    4m33.141s
user    1m20.940s
sys     1m44.451s
mkc
fuente
El último sedestá mal escrito. Edité esta publicación ayer para arreglar el último sedcomando que debería ser time sed -i '/original/ s//ketan/g' wiki10gby no time sed -i '/ketan/ s//original/g' wiki10gb. Revertiré mi edición hoy porque 1. las veces ya no coinciden con el comando y 2. He realizado la misma prueba con GNU sed en un archivo de 3+ GB y no observo ninguna diferencia entre las dos sedalternativas. Sospecho que la diferencia en los tiempos se debe a la falta de ortografía.
xhienne
@xhienne No estoy seguro de lo que quieres decir con escribir mal. En la primera ejecución, estoy sustituyendo la palabra 'original' con 'ketan' y en la segunda estoy sustituyendo el término 'ketan' con el término 'original', lo que da como resultado el mismo número de sustituciones en cualquier caso.
mkc
1
Estaba aplicando una "solución" informada por un nuevo usuario con poca reputación. Ahora entiendo lo que hiciste. Sin embargo, si desea probar que una sintaxis es mejor que otra, debe hacer exactamente la misma operación, que no es el caso aquí (en cuanto a CPU, buscar una cadena de 5 caracteres no es lo mismo que buscar un Cadena de 7 caracteres). Además, este tipo de prueba en un archivo de 10 GB depende en gran medida de la carga de su máquina (CPU, disco). Vi muchas fluctuaciones en los timeresultados personalmente, pero en general, no hubo diferencia en el tiempo.
xhienne
Creo que esto está relacionado: vea la respuesta aceptada aquí, stackoverflow.com/questions/11145270/… >> sed transmite todo el archivo, pero como se señala en esta respuesta, la especificación del número de línea (si se conoce) ayuda: en mi caso , un aumento de ~ 2 veces en la velocidad de ejecución (GNU sed 4.5). Puede grep -n o ripgrep (rg) para buscar números de línea, basados ​​en búsquedas de patrones. En efecto, especificar el número de línea es como tener un resultado de búsqueda en ese archivo, según la respuesta anterior.
Victoria Stuart
1

La respuesta corta es "No": su factor limitante en este tipo de operación es el disco IO. No hay forma de transmitir 25 GB de un disco más rápido. Es posible que obtenga una mejora menor si no edita en el lugar y escribe el resultado de la sedunidad en una unidad separada (si tiene una disponible), porque de esa manera puede leer de una, mientras escribe a otra y hay un poco menos contención como resultado.

Es posible que pueda acelerarlo un poco al no usar el motor de expresiones regulares para cada línea, por lo que, por ejemplo, usando perl (estoy bastante seguro de que puede hacer esto, sedpero no sé la sintaxis), esto comenzará desde línea 10,000 en adelante.

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

Y si hay algún tipo de complicaciones en los RE (metacaracteres), minimizarlos mejorará ligeramente la eficiencia del motor regex.

Sobrique
fuente
1
En sed eso seríased -i '10000,$ s/old_text/new_text/g'
Dani_l
Encantador. No sé cómo se sedcompara: supongo que es marginalmente más rápido, pero no mucho debido al tamaño del archivo.
Sobrique
Supongo que perl es más rápido que sed, pero sed es algo menos críptico, o más bien requiere menos de una curva de aprendizaje inicial.
Dani_l
1
Véase, ahora me he dicho lo contrario - se puede (casi) de escritura seden perl, pero este último también le permite escribir guiones más prolija también.
Sobrique
0

Si los textos nuevos y antiguos tienen la misma longitud, puede buscar en el archivo y escribir solo los bytes modificados, en lugar de copiar todo el archivo. De lo contrario, queda atrapado en mover muchos datos.

Nota: esto es complicado e implica escribir código personalizado.

Consulte la página de manual de fseek si está trabajando en C o C ++, o sus envoltorios de idiomas preferidos para las llamadas al sistema de búsqueda y escritura.

Si insiste en usar solo la línea de comandos y puede obtener los desplazamientos de bytes del texto, puede escribir el texto de reemplazo en su lugar con comandos "dd" cuidadosamente escritos.

momento robado
fuente