Grepping по огромной производительности файла

Это @rozcietrzewiacz - отличное решение, но если Вы все еще хотите остаться с текстовыми файлами (как возвращено file), можно тщательно создать массив имен файлов, затем выполнить Ваш grep команда на том массиве.

Я предполагаю следующее:

  • ни в каком имени файла существует новая строка (но пробелы могут присутствовать);
  • a file util та поддержка -0 и -i опции;
  • GNU sed или поддержка sed \x коды символа exadecimal.

Вот пример

#!/bin/bash

get_file_list() {
  local path="$1"
  find "$path" -type f -exec file -0i {} + |
    sed -n '/\x00  *text\//s/\x00.*//p'
}

list=()
while IFS= read -r line; do
  list+=("$line")
done < <(get_file_list .)

# to choose options and pattern
grep -i pattern "${list[@]}"

sed команда берет последовательность строки текста, прибывающего из file, составленный из имени файла, байта NUL и типа пантомимы. Если во второй части (после NUL) существует слово text/ затем удалите ту часть и только распечатайте имя файла, иначе ничего не распечатайте.

4
30.05.2012, 00:51
4 ответа

Ключ к производительности читает огромный файл только однажды.

Можно передать несколько шаблонов grep путем помещения их на отдельные строки. Это обычно делается, говоря grep читать шаблоны из файла:

grep -F -f 300KFile 30MFile

Это производит соответствия в порядке большого файла и печатает строки, которые соответствуют нескольким шаблонам только однажды. Кроме того, это ищет шаблоны где угодно в строке; например, если файл шаблона содержит 1234, затем строки такой как 123456,345678,2348962342 и 478912,1211138,1234 будет соответствовать.

Можно ограничить точными совпадениями столбца путем предварительной обработки шаблона. Например, если шаблоны не содержат специального символа ()?*+\|[]{}:

<300KFile sed -e 's/^/(^|,)/' -e 's/$/($|,)/' |
grep -E -f - 30MFile

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

<300KFile sed -e 's/^/(^|,)/' -e 's/$/($|,)/' |
grep -E -f - 30MFile |
perl -l -F, -ape '
    BEGIN {
        open P, "300KFile" or die;
        %patterns = map {chomp; $_=>1} <P>;
        close P;
    }
    foreach $c (@F) {
        if ($patterns{$c}) {
            print;
            delete $patterns{$c};
        }
    }
'
6
27.01.2020, 20:48
  • 1
    , когда я использую grep-F-f 300KFile 30MFile> result.txt это в основном, воссоздал 30MFile в result.txt. Я делаю что-то не так? –  marcio_rogerio 30.05.2012, 05:18
  • 2
    @marcio_rogerio Делает у Вас есть пустая строка в 300KFile? Это соответствовало бы всем строкам в 30MFile. –  Gilles 'SO- stop being evil' 30.05.2012, 11:11
  • 3
    прямо на пятне! это зафиксировало его! это работало меньше чем через 30 секунд!!!большое спасибо! –  marcio_rogerio 30.05.2012, 15:36

Можно ли выполнить следующее?

grep -Ff FILE_A FILE_B > FILE_C

Теперь можно запустить скрипт на файлах A и C только.

Обновление: Ожидать... Это сохраняет порядок?

Другое обновление: еще Некоторая обработка необходима для хранения порядка. Это дает мне те же результаты как Ваш исходный сценарий. Протестированный на 300K строках в FILE_A и только 300K строки в FILE_B, 125 минут по сравнению с 14 secs.

#! /bin/bash
grep -Ff FILE_A FILE_B > FILE_B_TMP
grep -oFf FILE_A FILE_B_TMP > FILE_A_SHUFF
grep -Ff FILE_A_SHUFF FILE_A > FILE_A_TMP

while read -r line; do
   grep -F -m1 "$line" FILE_B_TMP
done < FILE_A_TMP > result.txt
4
27.01.2020, 20:48
  • 1
    я верю этому, должен сохранить порядок файла b. –  Kevin 30.05.2012, 02:44
  • 2
    , когда я использую grep-F-f 300KFile 30MFile> result.txt это в основном, воссоздал 30MFile в result.txt. Я делаю что-то не так? –  marcio_rogerio 30.05.2012, 05:18
  • 3
    @marcio_rogerio: Это просто означает, что почти каждая строка из 300K файла имеет соответствие где-нибудь в 30M файл. В таком случае мой сценарий не поможет Вам. Можно ли дать нам, больше информации о данных - т.е. действительно ли длина полей является постоянным и т.д.? –  choroba 30.05.2012, 09:42

Я полагаю, что коммуникация может сделать лучшую производительность:

comm -12 300KFile <(sed 's/,.*//' 30MFile)

PS. Я не уверен если строка 123123 fromm 300KFile должен соответствовать для строкового представления gdwyedg,123123,hfsjdkfh в 30M файл. Как в Вашем сценарии это соответствует, но в моем сценарии это не делает.

0
27.01.2020, 20:48

Я полагаю, что grep базировался, решения все еще должны сравнить каждую запись в FILE_A с каждой записью в FILE_B. С тех пор, по крайней мере, n-1 записи в FILE_A не будет соответствовать определенной записи в FILE_B, существует большое дублирование в этом подходе. Если бы с другой стороны, файлы были отсортированы затем, то было бы возможно отбросить большое количество тестов для каждого сравнения. Следовательно, что-то как....

#!/bin/bash

# NB a faster solution would be to sort the smaller file in a seperate process
# you might also want to set a buffer size for large files
sort $1 > /tmp/$$.a
sort $2 > /tmp/$$.b

join -j1 -t',' /tmp/$$.a /tmp/$$.b

rm -f /tmp/$$.?

(не протестированный)

Но обратите внимание, что порядок записей будет изменен, это предполагает, что Вы хотите соответствовать на определенном столбце данных в FILE_B, и также сортировка представляет издержки - но результат должен быть быстрее для этих размеров файла.

0
27.01.2020, 20:48

Теги

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