Decir que tengo un archivo de texto grande (> 2 GB) y sólo quiero que catlas líneas Xa Y(por ejemplo, 57.89 millón a 57,890,010).
Por lo que entiendo, puedo hacer esto headentrando tailo viceversa, es decir
head -A /path/to/file | tail -B
o alternativamente
tail -C /path/to/file | head -D
donde A, B, Cy Dpuede ser calculado a partir del número de líneas en el archivo, Xy Y.
Pero hay dos problemas con este enfoque:
- Usted tiene que calcular A,B,CyD.
- Los comandos podrían pipeentre sí muchas más líneas de las que estoy interesado en leer (por ejemplo, si estoy leyendo solo unas pocas líneas en medio de un archivo enorme)
¿Hay alguna manera de que el shell simplemente funcione y genere las líneas que quiero? (mientras proporciona solo Xy Y)?
                    
                        tail
                                cat
                                large-files
                                head
                                
                    
                    
                        Amelio Vazquez-Reina
fuente
                
                fuente

Respuestas:
Sugiero la
sedsolución, pero en aras de la integridad,Para cortar después de la última línea:
Prueba de velocidad:
seq 100000000 > test.inrealtiempo según lo informado porbash's incorporadotimeEstos no son puntos de referencia precisos, pero la diferencia es clara y lo suficientemente repetible * como para dar una buena idea de la velocidad relativa de cada uno de estos comandos.
*: Excepto entre los dos primeros,
sed -n p;qyhead|tail, que parecen ser esencialmente lo mismo.fuente
tail -n +50000000 test.in | head -n10, que a diferenciatail -n-50000000 test.in | head -n10daría el resultado correcto?tail+|heades más rápido en un 10-15% que sed, he agregado ese punto de referencia.-cpara omitir caracteres,tail+|heades instantánea. Por supuesto, no puede decir "50000000" y puede que tenga que buscar manualmente el inicio de la sección que está buscando.Si desea líneas X a Y inclusive (comenzando la numeración en 1), use
tailleerá y descartará las primeras líneas X-1 (no hay forma de evitarlo), luego leerá e imprimirá las siguientes líneas.headleerá e imprimirá el número de líneas solicitado, luego saldrá. Cuandoheadsale,tailrecibe una señal SIGPIPE y muere, por lo que no habrá leído más del tamaño de un búfer (generalmente unos pocos kilobytes) de líneas del archivo de entrada.Alternativamente, como sugirió gorkypl , use sed:
Sin embargo, la solución sed es significativamente más lenta (al menos para las utilidades GNU y Busybox; sed podría ser más competitiva si extrae una gran parte del archivo en un sistema operativo donde la tubería es lenta y sed es rápida). Aquí hay puntos de referencia rápidos en Linux; los datos fueron generados por
seq 100000000 >/tmp/a, el entorno es Linux / amd64,/tmpes tmpfs y la máquina está inactiva y no se intercambia.Si conoce el rango de bytes con el que desea trabajar, puede extraerlo más rápido saltando directamente a la posición inicial. Pero para las líneas, debe leer desde el principio y contar las nuevas líneas. Para extraer bloques de x inclusive a y exclusivo a partir de 0, con un tamaño de bloque de b:
fuente
tail will read and discard the first X-1 lineparece evitarse cuando se da el número de líneas desde el final. En tal caso, la cola parece leer hacia atrás desde el final de acuerdo con los tiempos de ejecución. Por favor lea:http://unix.stackexchange.com/a/216614/79743.tail(incluida GNU tail) tienen heurísticas para leer desde el final. Eso mejora latail | headsolución en comparación con otros métodos.El
head | tailenfoque es una de las mejores y más "idiomáticas" formas de hacer esto:Como señaló Gilles en los comentarios, una forma más rápida es
La razón por la que esto es más rápido es que las primeras líneas X - 1 no necesitan pasar por la tubería en comparación con el
head | tailenfoque.Su pregunta como formulada es un poco engañosa y probablemente explica algunas de sus dudas infundadas hacia este enfoque.
Usted dice que usted tiene que calcular
A,B,C,Dpero como se puede ver, no es necesario el número de líneas del archivo y como máximo 1 cálculo es necesario, que la cáscara puede hacer por usted de todos modos.Le preocupa que la tubería lea más líneas de las necesarias. De hecho, esto no es cierto:
tail | heades lo más eficiente posible en términos de E / S de archivo. Primero, considere la cantidad mínima de trabajo necesario: para encontrar la línea X 'th en un archivo, la única forma general de hacerlo es leer cada byte y detenerse cuando cuenta X símbolos de nueva línea ya que no hay forma de adivinar el archivo desplazamiento de la línea X 'th. Una vez que llegue a la línea * X *, debe leer todas las líneas para imprimirlas, deteniéndose en la línea Y '. Por lo tanto, ningún enfoque puede salirse con la lectura de menos de líneas Y Ahora,head -n $Ylee no más que Ylíneas (redondeadas a la unidad de memoria intermedia más cercana, pero las memorias intermedias si se usan correctamente mejoran el rendimiento, por lo que no hay que preocuparse por esa sobrecarga). Además,tailno leerá más quehead, por lo tanto, hemos demostrado quehead | taillee la menor cantidad posible de líneas (de nuevo, además de un almacenamiento intermedio insignificante que estamos ignorando). La única ventaja de eficiencia de un enfoque de herramienta única que no utiliza tuberías es menos procesos (y, por lo tanto, menos gastos generales).fuente
La forma más ortodoxa (pero no la más rápida, como señaló Gilles anteriormente) sería utilizarla
sed.En tu caso:
La
-nopción implica que solo las líneas relevantes se imprimen en stdout.La p al final del número de la línea de llegada significa imprimir líneas en un rango dado. La q en la segunda parte del script ahorra algo de tiempo al omitir el resto del archivo.
fuente
sedytail | headque se acerca a la par, pero resulta quetail | heades significativamente más rápido (véase mi respuesta ).tail/headse consideran más "ortodoxa", ya que el recorte de los extremos de un archivo es precisamente lo que están hechos para. En esos materiales,sedsolo parece ingresar a la imagen cuando se requieren sustituciones, y se expulsa rápidamente de la imagen cuando comienza a suceder algo mucho más complejo, ya que su sintaxis para tareas complejas es mucho peor que AWK, que luego se hace cargo .Si conocemos el rango para seleccionar, desde la primera línea:
lStarthasta la última línea:lEndpodríamos calcular:Si conocemos la cantidad total de líneas:
lAlltambién podríamos calcular la distancia hasta el final del archivo:Entonces sabremos ambos:
Elegir el más pequeño de todos:
tailnumbercomo este:Nos permite usar el comando de ejecución consistentemente más rápido:
Tenga en cuenta el signo más ("+") adicional cuando
$linestartse selecciona.La única advertencia es que necesitamos el recuento total de líneas, y eso puede tomar un tiempo adicional para encontrarlo.
Como es habitual con:
Algunas veces medidas son:
Tenga en cuenta que los tiempos cambian drásticamente si las líneas seleccionadas están cerca del inicio o cerca del final. Un comando que parece funcionar bien en un lado del archivo, puede ser extremadamente lento en el otro lado del archivo.
fuente
Hago esto con bastante frecuencia y escribí este guión. No necesito encontrar los números de línea, el script lo hace todo.
fuente
tail|head, que se ha discutido ampliamente en la pregunta y las otras respuestas, y el 90% determina los números de línea donde aparecen las cadenas / patrones especificados, lo que no era parte de la pregunta . PD: siempre debe citar los parámetros y variables de su shell; por ejemplo, "$ 3" y "$ 4".