Использование 'head' или 'tail' в ОГРОМНОМ текстовом файле - 19 ГБ

9431
nicorellius

У меня проблема с просмотром фрагментов очень большого текстового файла. Этот файл, размером примерно 19 ГБ, очевидно, слишком велик для просмотра любыми традиционными способами.

Я попытался head 1и tail 1( head -n 1и tail -n 1) с обеими командами по-разному соединены (чтобы получить кусок в середине) без удачи. Моя Linux-машина с Ubuntu 9.10 не может обработать этот файл.

Как мне обработать этот файл? Моя конечная цель - отточить линии 45000000 и 45000100.

13
Думая о написании быстрого скрипта Python для чтения строк и печати тех, которые мне нужны, но я могу себе представить, что это займет много времени ... nicorellius 12 лет назад 0
Все ли линии одинаковой длины? Paul 12 лет назад 0
@Paul - к сожалению, они не одинаковой длины. nicorellius 12 лет назад 0
Вы можете попробовать [`split`] (http://linux.die.net/man/1/split), чтобы облегчить работу с большим файлом. iglvzx 12 лет назад 0
Хорошо. Любая обработка файла такого размера потребует времени, поэтому ответы ниже помогут в этом. Если вы хотите извлечь только часть, которую вы ищете, и можете приблизительно оценить, где она находится, вы можете использовать `dd`, чтобы получить бит, который вам нужен. Например, `dd if = bigfile of = extractfile bs = 1M skip = 10240 count = 5` извлечет 5 МБ из файла, начиная с точки 10 ГБ. Paul 12 лет назад 1
Да, я согласен с вами, Пол. Я написал скрипт на Python, и обработка файла определенно заняла целую вечность. У меня сейчас работает `sed`, и я думаю, что это займет довольно много времени. Но тестирование с началом файла оказывается многообещающим. Благодарю. nicorellius 12 лет назад 0

4 ответа на вопрос

11
Kyle Jones

Вы должны использовать sed.

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

Это говорит sedо необходимости печатать строки 45000000-45000100 включительно и выходить из строки 45000101.

Это все еще очень медленно, почти как голова -45000000,45000100p bigfile | tail -100> сохраненные линии Dmitry Polushkin 9 лет назад 1
`tail + | head` быстрее на 10-15%. erich 6 лет назад 0
4
Der Hochstapler

Создайте базу данных MySQL с одной таблицей, которая имеет одно поле. Затем импортируйте ваш файл в базу данных. Это позволит легко найти определенную строку.

Я не думаю, что что-то еще может быть быстрее (если headи tailуже не получится ). В конце концов, приложение, которое хочет найти строку n, должно выполнить поиск по всему файлу, пока не найдет nновые строки. Без какого-либо поиска (строковый индекс к байтовому смещению в файл) невозможно добиться лучшей производительности.

Учитывая, как легко создать базу данных MySQL и импортировать в нее данные, я чувствую, что это жизнеспособный подход.

Вот как это сделать:

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 будет файл, который вы хотите прочитать.

Правильный синтаксис для импорта файла с разделенными табуляцией значениями в каждой строке:

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

Еще одним важным преимуществом этого является то, что, если вы решите позднее извлечь другой набор строк, вам не придется ждать часами обработки снова (если, конечно, вы не удалите базу данных).

Так что это действительно хорошее решение. Я получил его для работы с командой `sed` ниже и определил мои строки. Но теперь у меня есть дополнительный вопрос, для которого метод базы данных может быть лучше подходит. Теперь мне нужно удалить пару сотен строк из файла. nicorellius 12 лет назад 0
Я уверен, что "sed" тоже может это сделать. Конечно, если бы у вас были данные в базе данных, было бы тривиально экспортировать новый файл только с теми строками, которые вы хотите. Der Hochstapler 12 лет назад 0
Еще раз спасибо. Я взял ответ «sed» (потому что это доставило мне больше немедленного удовольствия; -), но дал вам возможность проголосовать, потому что я буду использовать ваш метод в будущем. Я ценю его. nicorellius 12 лет назад 0
Я пытался использовать вышеописанный код SQL, и он, похоже, обрабатывался, но затем, когда я запустил запрос для просмотра моих строк, он просто дал мне первый столбец строки с разделителями табуляции. Каждая из строк разделена табуляцией. Какой совет вы могли бы дать мне, чтобы все строки были в таблице, как и ожидалось? nicorellius 12 лет назад 0
Вы можете попробовать добавить `FIELDS TERMINATED BY '\ n'` в строку [` LOAD DATA`] (http://dev.mysql.com/doc/refman/5.1/en/load-data.html). Der Hochstapler 12 лет назад 1
Хорошо спасибо. Не слишком знаком с этим синтаксисом, но получаю ошибку при использовании этого: `LOAD DATA INFILE '/ tmp / my_large_file' INTO TABLE helperTable (lineContent) FIELDS TERMINATED BY '\ n';` Я искал по документам, и ничего не происходит высовываться. Какие-нибудь мысли? Извините, что беспокою вас этим. nicorellius 12 лет назад 0
Извините, в моем коде произошла ошибка. Я также добавил правильный синтаксис для вашего случая (проверено на этот раз). Der Hochstapler 12 лет назад 1
Круто - спасибо - я опробую это позже сегодня. Ценю твою помощь. nicorellius 12 лет назад 0
1
Anssi

Two good old tools for big files are joinand split. You can use split with --lines=<number> option that cut file to multiple files of certain size.

For example split --lines=45000000 huge_file.txt. The resulted parts would be in xa, xb, etc. Then you can head the part xb which would include the the lines you wanted. You can also 'join' files back to single big file.

Круто, спасибо, я полностью забыл про команду split. siliconrockstar 7 лет назад 0
0
erich

У вас есть нужные инструменты, но вы используете их неправильно. Как было сказано ранее в U & L, tail -n +X file | head -n Y(обратите внимание, что +) на 10-15% быстрее, чем sedдля линий Y, начинающихся с X. И удобно, что вам не нужно явно exitобрабатывать процесс, как с sed.

tail будет читать и отбрасывать первые строки X-1 (пути назад нет), затем читать и печатать следующие строки. head прочитает и напечатает требуемое количество строк, затем выйдет. Когда голова выходит, tail получает сигнал SIGPIPE и умирает, поэтому он не будет считывать из входного файла строки размером больше буфера (обычно несколько килобайт).

Похожие вопросы