Reemplace la cadena que contiene una nueva línea en un archivo enorme

Reemplace la cadena que contiene una nueva línea en un archivo enorme

¿Alguien conoce una herramienta no basada en líneas para buscar/reemplazar cadenas "binarias" de una manera algo eficiente en memoria?Veresta preguntatambién.

Tengo un archivo de texto de +2 GB que me gustaría procesar de manera similar a lo que parece hacer esto:

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

Eso significa que quiero eliminar todas las nuevas líneas que ocurren después de >, pero no en ningún otro lugar, por lo que eso descarta tr -d.

Este comando (que obtuve dela respuesta a una pregunta similar) falla con couldn't re-allocate memory:

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

Entonces, ¿existen otros métodos sin recurrir a C? Odio Perl, pero estoy dispuesto a hacer una excepción en este caso :-)

No estoy seguro de ningún carácter que no aparezca en los datos, por lo que el reemplazo temporal \ncon otro carácter es algo que me gustaría evitar si es posible.

¿Alguna buena idea, alguien?

Respuesta1

Esto es realmente trivial en Perl, ¡no deberías odiarlo!

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

Explicación

  • -i: edite el archivo en su lugar y cree una copia de seguridad del original llamada file.bak. Si no desea una copia de seguridad, úsela perl -i -peen su lugar.
  • -pe: lea el archivo de entrada línea por línea e imprima cada línea después de aplicar el script proporcionado como -e.
  • s/>\n/>/: la sustitución, al igual que sed.

Y aquí hay un awkenfoque:

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

Respuesta2

Una perlsolución:

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

Explicación

  • s///se utiliza para la sustitución de cadenas.
  • (?<=>)es un patrón de búsqueda hacia atrás.
  • \ncoincide con la nueva línea.

Todo el patrón significa eliminar todas las nuevas líneas que tienen >antes.

Respuesta3

Qué tal esto:

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

Para GNU sed, también puede intentar agregar la opción -u( --unbuffered) según la pregunta. GNU sed también está contento con esto como una simple frase:

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

Respuesta4

sedno proporciona una forma de emitir resultados sin una nueva línea final. Su enfoque Nfunciona fundamentalmente, pero almacena líneas incompletas en la memoria y, por lo tanto, puede fallar si las líneas se vuelven demasiado largas (las implementaciones sed generalmente no están diseñadas para manejar líneas extremadamente largas).

Puedes usar awk en su lugar.

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

Un enfoque alternativo es cambiar trel carácter de nueva línea por un carácter "aburrido" que aparece con frecuencia. El espacio podría funcionar aquí: elija un carácter que tienda a aparecer en cada línea o al menos en una gran proporción de líneas de sus datos.

tr ' \n' '\n ' | sed 's/> />/g' | tr '\n ' ' \n'

información relacionada