grep Extract Speci c шаблон из большого файла 190 ГБ - PullRequest
1 голос
/ 18 февраля 2020

Мне нужно извлечь адреса электронной почты из большого плоского файла 190 ГБ (только журнал ошибок), который я разрезал на файлы размером 5 МБ. (с 152 353 216 строками)

Команда grep работает хорошо, но память быстро насыщается, и я получаю ошибки.

Содержимое файлов не отформатировано, поэтому я должен использовать regexp.

grep -r -E -h -o "\b(pattern)\b" /dir/* > outs.txt

Как обрабатывать файлы один за другим?

Ответы [ 3 ]

2 голосов
/ 18 февраля 2020

В зависимости от ваших данных, производительности вашего диска и вашего процессора, вы можете улучшить работу с GNU Parallel . Если вы используете параметр --pipepart, он также разделит ваш файл объемом 190 ГБ для вас без создания временных файлов.

Итак, я создал файл 5 ГБ с 100000000 строками, используя Perl, например:

perl -E 'for($i=0;$i<100000000;$i++){say "Line $i,field2,field3,junk,junk,junk",int rand 1000000}' > BigBoy.txt

Первые 3 строки выглядят так:

Line 0,field2,field3,junk,junk,junk514649
Line 1,field2,field3,junk,junk,junk257773
Line 2,field2,field3,junk,junk,junk203414

Затем я рассчитал grep на 58 секунд для этого файла, который выдал 88 строк вывода:

time grep "junk426888$" BigBoy.txt

Затем я рассчитал GNU Parallel на 11 секунд для того же выхода:

time parallel -a BigBoy.txt --pipepart --block -1 grep "junk426888$"
1 голос
/ 18 февраля 2020

Самый простой (но, вероятно, не самый быстрый) способ обработки всех файлов - это сделать это один за другим, используя al oop:

for file in /dir/*; do
  grep -r -E -h -o '\b(pattern)\b' "$file"
done > outs.txt

Затраты на запуск всех этих grep s потенциально очень важен, поэтому, возможно, вы могли бы использовать xargs, чтобы помочь:

find /dir/ -maxdepth 1 -type f -print0 |
  xargs -0 -n 1000 grep -r -E -h -o '\b(pattern)\b' > outs.txt

Это использует find для создания списка файлов в dir и безопасно передает их xargs, разделенных нулевым байтом \0 (символ гарантированно отсутствует в имени файла). xargs затем передает файлы на grep партиями по 1000.

(я предполагаю, что у вас есть GNU-версии find и xargs здесь для find -print0 и xargs -0 )

1 голос
/ 18 февраля 2020

Используйте xargs для выполнения команды grep для каждого файла отдельно (а не для всех файлов)

ls -1 /dir/ | xargs -n 1 -I '{}' grep -r -E -h -o "\b(pattern)\b" '{}' > outs.txt

Флаг -n 1 указывает xargs запускать один процесс для каждого файла.

Аргумент -I '{}' указывает xargs заменить '{}' на имя файла.

Другими словами, если /dir содержит file1, file2, ... выполняется последовательно

grep -r -E -h -o "\b(pattern)\b" /dir/file1
grep -r -E -h -o "\b(pattern)\b" /dir/file2
grep -r -E -h -o "\b(pattern)\b" /dir/file3...
...