Usando 'head' o 'tail' en un archivo de texto ENORME - 19 GB

15

Tengo un problema con la visualización de fragmentos de un archivo de texto muy grande. Este archivo, de aproximadamente 19 GB, es obviamente demasiado grande para verlo por cualquier medio tradicional.

He intentado head 1y tail 1( head -n 1y tail -n 1) con ambos comandos conectados de varias maneras (para llegar a una pieza en el medio) sin suerte. Mi máquina Linux que ejecuta Ubuntu 9.10 no puede procesar este archivo.

¿Cómo manejo este archivo? Mi objetivo final es afinar las líneas 45000000 y 45000100.

nicorellius
fuente
Pensando en escribir una secuencia de comandos de Python rápida para leer las líneas e imprimir los archivos que necesito, pero me puedo imaginar esta tomando mucho tiempo ...
nicorellius
¿Todas las líneas tienen la misma longitud?
Paul
@Paul - desafortunadamente, no tienen la misma longitud.
nicorellius
Puede intentar splithacer que el archivo grande sea más fácil de trabajar.
iglvzx
1
Okay. Cualquier procesamiento de un archivo tan grande llevará tiempo, por lo que las respuestas a continuación lo ayudarán. Si desea extraer solo la parte que está buscando y puede estimar aproximadamente dónde está, puede usar ddpara obtener el bit que busca . Por ejemplo dd if=bigfile of=extractfile bs=1M skip=10240 count=5, extraerá 5 MB del archivo a partir del punto de 10 GB.
Paul

Respuestas:

11

Debe utilizar sed.

sed -n -e 45000000,45000100p -e 45000101q bigfile > savedlines

Esto le indica sedque imprima las líneas 45000000-45000100 inclusive y que salga en la línea 45000101.

Kyle Jones
fuente
1
Todavía es muy lento, casi como la cabeza -45000000,45000100p bigfile | cola -100> líneas guardadas
Dmitry Polushkin
tail+|heades más rápido en un buen 10-15%.
Erich
4

Cree una base de datos MySQL con una sola tabla que tenga un solo campo. Luego importe su archivo a la base de datos. Esto hará que sea muy fácil buscar una determinada línea.

No creo que cualquier otra cosa podría ser más rápido (si heady tailno haya superado). Al final, la aplicación que quiere encontrar la línea ntiene que buscar en todo el archivo hasta que encuentre nnuevas líneas. Sin algún tipo de búsqueda (índice de línea para desplazamiento de bytes en el archivo) no se puede lograr un mejor rendimiento.

Dado lo fácil que es crear una base de datos MySQL e importar datos en ella, siento que este es un enfoque viable.

Aquí está cómo hacerlo:

DROP DATABASE IF EXISTS helperDb;
CREATE DATABASE `helperDb`;
CREATE TABLE `helperDb`.`helperTable`( `lineIndex` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `lineContent` MEDIUMTEXT , PRIMARY KEY (`lineIndex`) );
LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable (lineContent);
SELECT lineContent FROM helperTable WHERE ( lineIndex > 45000000 AND lineIndex < 45000100 );

/tmp/my_large_file sería el archivo que quieres leer.

La sintaxis correcta para importar un archivo con valores delimitados por tabulaciones en cada línea es:

LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable FIELDS TERMINATED BY '\n' (lineContent);

Otra ventaja importante de esto es que si luego decide extraer otro conjunto de líneas, no tendrá que esperar horas para el procesamiento nuevamente (a menos que elimine la base de datos, por supuesto).

Der Hochstapler
fuente
Entonces esta es una buena solución, de hecho. Lo hice funcionar con el sedcomando a continuación, e identifiqué mis líneas. Pero ahora tengo una pregunta de seguimiento para la cual el método de base de datos puede ser más adecuado. Ahora necesito eliminar un par de cientos de líneas del archivo.
nicorellius
Estoy seguro de que sedpodría hacer eso también. Por supuesto, si tuviera los datos en la base de datos, sería trivial exportar un nuevo archivo con solo las líneas que desea.
Der Hochstapler
Gracias de nuevo. Tomé la sedrespuesta (porque me dio un placer más inmediato; -) pero le di un voto positivo porque usaré su método en el futuro. Lo aprecio.
nicorellius
1
Podría intentar agregar un FIELDS TERMINATED BY '\n'a la LOAD DATAlínea.
Der Hochstapler
1
Lo siento, hubo un error en mi código. También agregué la sintaxis correcta para su caso (probado esta vez).
Der Hochstapler
1

Dos buenas herramientas antiguas para archivos grandes son joiny split. Puede usar la --lines=<number>opción dividir con que corta el archivo a varios archivos de cierto tamaño.

Por ejemplo split --lines=45000000 huge_file.txt. Las partes resultantes estarían en xa, xb, etc. Luego, puede headla parte xb que incluiría las líneas que deseaba. También puede 'unir' archivos a un solo archivo grande.

Anssi
fuente
Impresionante, gracias, me olvidé por completo del comando dividir.
siliconrockstar
0

Tiene las herramientas correctas pero las está utilizando incorrectamente. Como se respondió anteriormente en U&L, tail -n +X file | head -n Y(tenga en cuenta que +) es 10-15% más rápido que sedpara las líneas Y que comienzan en X. Y convenientemente, no tiene que explícitamente exitel proceso como con sed.

tail leerá y descartará las primeras líneas X-1 (no hay forma de evitarlo), luego leerá e imprimirá las siguientes líneas. head leerá e imprimirá el número de líneas solicitado, luego saldrá. Cuando sale la cabeza, la cola recibe una señal SIGPIPE y muere, por lo que no habrá leído más del valor de un tamaño de búfer (generalmente unos pocos kilobytes) de líneas del archivo de entrada.

Erich
fuente