Cuál es una buena forma de extraer, digamos, las líneas 20 a 45 de un archivo de texto enorme. No interactivamente, por supuesto!
Cuál es una buena forma de extraer, digamos, las líneas 20 a 45 de un archivo de texto enorme. No interactivamente, por supuesto!
Respuestas:
tu podrías intentar:
cat textfile | head -n 45 | tail -n 26
o
cat textfile | awk "20 <= NR && NR <= 45"
actualizar:
Como señaló Mahomedalid, catno es necesario y es un poco redundante, pero es un comando limpio y legible.
Si catte molesta, una mejor solución sería:
<textfile awk "20 <= NR && NR <= 45"
,operador de rango de awk .
Aún más simple:
sed -n '20,45p;45q' < textfile
El indicador -n deshabilita la salida predeterminada. El "20,45" aborda las líneas 20 a 45, inclusive. El comando "p" imprime la línea actual. Y la q se cierra después de imprimir la línea.
qcomando (todo a partir de ;) mejoró el rendimiento para mí al extraer una sola línea 26995107 de un archivo de 27169334 líneas.
Esta no es una respuesta, pero no puede publicarla como un comentario.
Mikeserv sugirió otra forma (muy rápida) de hacerlo aquí :
{ head -n 19 >/dev/null; head -n 26; } <infile
Usando el mismo archivo de prueba que aquí y el mismo procedimiento, aquí hay algunos puntos de referencia (líneas de extracción 1000020-1000045):
mikeserv :
{ head -n 1000019 >/dev/null; head -n 26; } <iplist
real 0m0.059s
Stefan :
head iplist -n 1000045 | tail -n 26
real 0m0.054s
Estas son, con mucho, las soluciones más rápidas y las diferencias son insignificantes (para una sola pasada) (intenté con diferentes rangos: un par de líneas, millones de líneas, etc.).
Sin embargo, hacerlo sin la tubería podría ofrecer una ventaja significativa para una aplicación que necesita buscar en múltiples rangos de líneas de manera similar, como:
for pass in 0 1 2 3 4 5 6 7 8 9
do printf "pass#$pass:\t"
head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES
... que imprime ...
pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000
... y solo lee el archivo una vez.
Las otras soluciones sed/ awk/ perlleen todo el archivo y, dado que se trata de archivos enormes, no son muy eficientes. Agregué algunas alternativas que exito quit después de la última línea en el rango especificado:
Stefan :
awk "1000020 <= NR && NR <= 1000045" iplist
real 0m2.448s
vs.
awk "NR >= 1000020;NR==1000045{exit}" iplist
real 0m0.243s
dkagedal ( sed):
sed -n 1000020,1000045p iplist
real 0m0.947s
vs.
sed '1,1000019d;1000045q' iplist
real 0m0.143s
Steven D :
perl -ne 'print if 1000020..1000045' iplist
real 0m2.041s
vs.
perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist
real 0m0.369s
awk NR==1000020,NR==1000045 textfileen su sistema.
ruby -ne 'print if 20 .. 45' file
python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'también? :-P Esto es algo que Ruby, inspirado en Perl, inspirado en awk / sed, puede hacer fácilmente.
Como sed y awk ya se tomaron, aquí hay una solución perl:
perl -nle "print if ($. > 19 && $. < 46)" < textfile
O, como se señala en los comentarios:
perl -ne 'print if 20..45' textfile
perl -ne'print if 20..45' textfile
awk NR==20,NR==45 textfilefunciona también y se lee fácilmente.