Usando 'head' o 'tail' sul file di testo ENORME - 19 GB


15

Ho un problema con la visualizzazione di blocchi di un file di testo molto grande. Questo file, circa 19 GB, è ovviamente troppo grande per essere visualizzato con qualsiasi mezzo tradizionale.

Ho provato head 1e tail 1( head -n 1e tail -n 1) con entrambi i comandi convogliati insieme in vari modi (per arrivare a un pezzo nel mezzo) senza fortuna. La mia macchina Linux che esegue Ubuntu 9.10 non è in grado di elaborare questo file.

Come gestisco questo file? Il mio obiettivo finale è affinare le linee 45000000 e 45000100.


Sto pensando di scrivere un veloce script in Python per leggere le righe e stampare quelle che devo archiviare, ma posso immaginare che ci
vorrà

Tutte le linee hanno la stessa lunghezza?
Paul,

@Paul - purtroppo non hanno la stessa lunghezza.
Nicorellius,

Puoi provare splita semplificare la gestione di file di grandi dimensioni.
iglvzx,

1
Ok. Qualsiasi elaborazione di un file così grande richiederà tempo, quindi le risposte che seguono aiuteranno questo. Se vuoi estrarre solo la parte che stai cercando e puoi stimare approssimativamente dove si trova puoi usare ddper ottenere il bit che cerchi. Ad esempio dd if=bigfile of=extractfile bs=1M skip=10240 count=5estrarrà 5 MB dal file a partire dal punto 10 GB.
Paul,

Risposte:


11

Si dovrebbe usare sed.

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

Questo indica seddi stampare le linee 45000000-45000100 incluse e di uscire dalla linea 45000101.


1
È ancora molto lento, quasi come la testa -45000000,45000100p bigfile | tail -100> savelines
Dmitry Polushkin il

tail+|headè più veloce di un buon 10-15%.
Erich,

4

Crea un database MySQL con una singola tabella che ha un singolo campo. Quindi importare il file nel database. Ciò renderà molto facile cercare una certa linea.

Non penso che nient'altro potrebbe essere più veloce (se heade tailgià fallire). Alla fine, l'applicazione che vuole trovare la linea ndeve cercare attraverso l'intero file fino a quando non trova nnuove righe. Senza una sorta di ricerca (dall'indice di linea all'offset di byte nel file) non è possibile ottenere prestazioni migliori.

Data la facilità con cui creare un database MySQL e importare i dati in esso, penso che questo sia un approccio praticabile.

Ecco come farlo:

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 sarebbe il file che vuoi leggere.

La sintassi corretta per importare un file con valori delimitati da tabulazioni su ciascuna riga è:

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

Un altro grande vantaggio di questo è, se in seguito decidi di estrarre un altro set di linee, non devi aspettare di nuovo le ore per l'elaborazione (a meno che tu non elimini il database ovviamente).


Quindi questa è davvero una buona soluzione. Ho ottenuto che funzioni con il sedcomando seguente e ho identificato le mie linee. Ma ora ho una domanda di follow-up per cui il metodo del database potrebbe essere più adatto. Ora devo eliminare un paio di centinaia di righe dal file.
Nicorellius,

Sono sicuro che sedpotrei farlo anche io . Naturalmente, se avessi i dati nel database, sarebbe banale esportare un nuovo file con solo le righe che desideri.
Der Hochstapler,

Grazie ancora. Ho preso la sedrisposta (perché mi ha dato un piacere più immediato; -) ma ti ho dato un voto positivo perché userò il tuo metodo in futuro. Lo apprezzo.
Nicorellius,

1
Potresti provare ad aggiungere FIELDS TERMINATED BY '\n'a alla LOAD DATAlinea.
Der Hochstapler,

1
Mi dispiace, c'è stato un errore nel mio codice. Ho anche aggiunto la sintassi corretta per il tuo caso (testato questa volta).
Der Hochstapler,

1

Due buoni vecchi strumenti per file di grandi dimensioni sono joine split. È possibile utilizzare la divisione con l' --lines=<number>opzione che consente di tagliare il file in più file di determinate dimensioni.

Per esempio split --lines=45000000 huge_file.txt. Le parti risultanti sarebbero in xa, xb, ecc. Quindi è possibile headla parte xb che includerebbe le linee desiderate. Puoi anche "unire" i file a un singolo file di grandi dimensioni.


Fantastico, grazie, mi ero completamente dimenticato del comando di divisione.
siliconrockstar,

0

Hai gli strumenti giusti ma li stai usando in modo errato. Come precedentemente risposto a U&L, tail -n +X file | head -n Y(nota il +) è del 10-15% più veloce rispetto sedalle linee Y che iniziano da X. E convenientemente, non è necessario esplicitamente exitil processo come con sed.

tail leggerà e scarterà le prime righe X-1 (non c'è modo di aggirarle), quindi legge e stampa le seguenti righe. head leggerà e stamperà il numero richiesto di righe, quindi uscirà. Quando head esce, tail riceve un segnale SIGPIPE e muore, quindi non avrà letto più del valore di una dimensione del buffer (in genere pochi kilobyte) di righe dal file di input.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.