Comando de shell de Linux para filtrar un archivo de texto por longitud de línea

19

Tengo una imagen de disco de 30 gb de una partición borked (creo dd if=/dev/sda1 of=diskimage) de la que necesito recuperar algunos archivos de texto. Las herramientas de tallado de datos foremostsolo funcionan en archivos con encabezados bien definidos, es decir, no en archivos de texto sin formato, por lo que he recurrido a mi buen amigo strings.

strings diskimage > diskstrings.txt produjo un archivo de texto de 3 gb que contiene un montón de cadenas, en su mayoría cosas inútiles, mezcladas con el texto que realmente quiero.

La mayor parte de la ruina tiende a ser muy larga e ininterrumpida de galimatías. Las cosas que me interesan están garantizadas en menos de 16 kb, por lo que voy a filtrar el archivo por la longitud de la línea. Aquí está el script de Python que estoy usando para hacerlo:

infile  = open ("infile.txt" ,"r");
outfile = open ("outfile.txt","w");
for line in infile:
    if len(line) < 16384:
        outfile.write(line)
infile.close()
outfile.close()

Esto funciona, pero para referencia futura: ¿Hay encantamientos mágicos de una sola línea (pensemos awk, sed) que filtrar un archivo de longitud de la línea?

Li-aung Yip
fuente

Respuestas:

28
awk '{ if (length($0) < 16384) print }' yourfile >your_output_file.txt

imprimiría líneas de menos de 16 kilobytes, como en su propio ejemplo.

O si te gusta Perl:

perl -nle 'if (length($_) < 16384) { print }' yourfile >your_output_file.txt
Janne Pikkarainen
fuente
Bueno, eso fue vergonzosamente simple. Gracias. :)
Li-aung Yip
También se agregó la versión de Perl :-)
Janne Pikkarainen
Y el script awk se puede escribir como awk 'length($0) < 16384' file > output, ya que la acción predeterminada es imprimir la línea.
Glenn Jackman
8

Esto es similar a la respuesta de Ansgar, pero un poco más rápido en mis pruebas:

awk 'length($0) < 16384' infile >outfile

Es la misma velocidad que las otras respuestas awk. Se basa en lo implícito printde una expresión verdadera, pero no necesita tomarse el tiempo para dividir la línea como lo hace Ansgar.

Tenga en cuenta que AWK le ofrece ifgratis. El comando anterior es equivalente a:

awk 'length($0) < 16384 {print}' infile >outfile

No hay explícito if(o su conjunto circundante de llaves) como en algunas de las otras respuestas.

Aquí hay una manera de hacerlo sed:

sed '/.\{16384\}/d' infile >outfile

o:

sed -r '/.{16384}/d' infile >outfile

que eliminan cualquier línea que contenga 16384 (o más) caracteres.

Para completar, así es como usaría sedpara guardar líneas más largas que su umbral:

sed '/^.\{0,16383\}$/d' infile >outfile
Pausado hasta nuevo aviso.
fuente
2

Puedes awkcomo:

$ awk '{ if (length($0) < 16384) { print } }' /path/to/text/file

Esto imprimirá las líneas más largas que menos de 16K caracteres (16 * 1024).

Puedes usar greptambién:

$ grep ".\{,16384\}" /path/to/text/file

Esto imprimirá las líneas en la mayoría de los 16K caracteres.

Khaled
fuente
No estoy seguro de que grepsea ​​una buena idea: es una expresión regular simple, sin duda, pero más costosa desde el punto de vista computacional que awk. "Un hombre con problemas dice" ¡Usaré expresiones regulares! "Ahora tiene dos problemas". ;)
Li-aung Yip
Es solo otra forma de hacerlo. La primera opción que publiqué fue usar awk.
Khaled
1
+1 para la
expresión regular
2

No es realmente diferente de las respuestas ya dadas, pero aún más breve:

awk -F '' 'NF < 16384' infile >outfile
Ansgar Esztermann
fuente