Tengo un archivo que contiene aproximadamente 10 millones de líneas.
Quiero eliminar todas las líneas del archivo que tengan menos de seis caracteres.
¿Cómo hago esto?
Tengo un archivo que contiene aproximadamente 10 millones de líneas.
Quiero eliminar todas las líneas del archivo que tengan menos de seis caracteres.
¿Cómo hago esto?
Respuestas:
Hay muchas maneras de hacer esto.
Utilizando grep
:
grep -E '^.{6,}$' file.txt >out.txt
Ahora out.txt
contendrá líneas que tienen seis o más caracteres.
Manera inversa:
grep -vE '^.{,5}$' file.txt >out.txt
Usando sed
, eliminando líneas de longitud 5 o menos:
sed -r '/^.{,5}$/d' file.txt
Forma inversa, líneas de impresión de longitud seis o más:
sed -nr '/^.{6,}$/p' file.txt
Puede guardar la salida en un archivo diferente usando el >
operador como grep
o editar el archivo en el lugar usando la -i
opción de sed
:
sed -ri.bak '/^.{6,}$/' file.txt
Se realizará una copia de seguridad del archivo original file.txt.bak
y se modificará el archivo modificado file.txt
.
Si no desea mantener una copia de seguridad:
sed -ri '/^.{6,}$/' file.txt
Usando shell, más lento, no hagas esto , esto es solo para mostrar otro método:
while IFS= read -r line; do [ "${#line}" -ge 6 ] && echo "$line"; done <file.txt
Utilizando python
, incluso más lento que grep
, sed
:
#!/usr/bin/env python2
with open('file.txt') as f:
for line in f:
if len(line.rstrip('\n')) >= 6:
print line.rstrip('\n')
Mejor usar la comprensión de la lista para ser más Pythonic:
#!/usr/bin/env python2
with open('file.txt') as f:
strip = str.rstrip
print '\n'.join([line for line in f if len(strip(line, '\n')) >= 6]).rstrip('\n')
Es muy simple:
grep ...... inputfile > resultfile #There are 6 dots
Esto es extremadamente eficiente, ya grep
que no intentará analizar más de lo que necesita, ni interpretará los caracteres de ninguna manera: simplemente envía una línea (completa) a stdout (que el shell luego redirige al archivo de resultados) tan pronto como vio 6 caracteres en esa línea ( .
en un contexto regexp coincide con cualquier 1 carácter).
Por lo tanto, grep solo generará líneas que tengan 6 (o más) caracteres, y las otras no se generarán por grep, por lo que no se convertirán en archivos de resultados.
La forma más rápida: compila y ejecuta este programa en C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFER_SIZE 1000000
int main(int argc, char *argv[]) {
int length;
if(argc == 3)
length = atoi(argv[2]);
else
return 1;
FILE *file = fopen(argv[1], "r");
if(file != NULL) {
char line[MAX_BUFFER_SIZE];
while(fgets(line, sizeof line, file) != NULL) {
char *pos;
if((pos = strchr(line, '\n')) != NULL)
*pos = '\0';
if(strlen(line) >= length)
printf("%s\n", line);
}
fclose(file);
}
else {
perror(argv[1]);
return 1;
}
return 0;
}
Compile con gcc program.c -o program
, ejecute con ./program file line_length
(where file
= ruta al archivo y line_length
= longitud mínima de línea, en su caso 6
; la longitud máxima de línea está limitada a 1000000
caracteres por línea; puede cambiar esto cambiando el valor de MAX_BUFFER_SIZE
).
(Truco para sustituir \n
con \0
encontrado aquí .)
Comparación con todas las otras soluciones propuestas para esta pregunta, excepto la solución de shell (prueba ejecutada en un archivo de ~ 91MB con 10M líneas con una longitud promedio de 8 caracteres):
time ./foo file 6
real 0m1.592s
user 0m0.712s
sys 0m0.160s
time grep ...... file
real 0m1.945s
user 0m0.912s
sys 0m0.176s
time grep -E '^.{6,}$'
real 0m2.178s
user 0m1.124s
sys 0m0.152s
time awk 'length>=6' file
real 0m2.261s
user 0m1.228s
sys 0m0.160s
time perl -lne 'length>=6&&print' file
real 0m4.252s
user 0m3.220s
sys 0m0.164s
sed -r '/^.{,5}$/d' file >out
real 0m7.947s
user 0m7.064s
sys 0m0.120s
./script.py >out
real 0m8.154s
user 0m7.184s
sys 0m0.164s
awk 'length>=6' file
length>=6
: si length>=6
devuelve VERDADERO, imprime el registro actual.perl -lne 'length>=6&&print' file
lenght>=6
devuelve VERDADERO, imprime el registro actual.% cat file
a
bb
ccc
dddd
eeeee
ffffff
ggggggg
% ./foo file 6
ffffff
ggggggg
% awk 'length>=6' file
ffffff
ggggggg
% perl -lne 'length>=6&&print' file
ffffff
ggggggg
awk
solución ...
sed
solución (sucede, lo sé). XD
pos
variable? Entiendo que devuelve un puntero al personaje line
con un carácter de nueva línea, pero parece que nunca lo usas. Y si no lo encuentra, simplemente configúrelo igual a \0
.
\0
( strchr()
devuelve un puntero NULL si no se encuentra el carácter). El punto es reemplazar cada nueva línea al final de cada línea \0
para que la nueva línea nunca se cuente por strlen()
: esto es para que la longitud siempre se pueda comparar con 6, independientemente de una posible nueva línea faltante en la última línea. Tratar de manera diferente solo la última línea sería mucho más eficiente, lo sé. Probablemente actualizaré esto más tarde.
grep
solución en el mismo archivo y en realidad es más rápido (probablemente porque strlen()
no es la mejor idea aquí) . Intentaré usar un getchar()
bucle para verificar solo el primer carácter N, supongo que eso debería mejorarlo visiblemente. Y sí, cualquier línea sobre la longitud del búfer simplemente se corta a la longitud del búfer.
Puede usar Vim en modo Ex:
ex -sc 'v/\v.{6}/d' -cx file
\v
enciende la magia
.{6}
encontrar líneas con 6 o más caracteres
v
invertir selección
d
Eliminar
x
guardar y cerrar
Solución de rubí:
$ cat input.txt
abcdef
abc
abcdefghijk
$ ruby -ne 'puts $_ if $_.chomp.length() >= 6 ' < input.txt
abcdef
abcdefghijk
Idea simple: redirija el archivo al stdin de ruby e imprima la línea desde el stdin solo si su longitud es mayor o igual a 6