Как использовать «grep -f file», если «file» содержит элементы, разделенные нулем? - PullRequest
0 голосов
/ 28 августа 2018

Мне нужно найти элементы, разделенные нулем, из многочисленных файлов (data2, data3, ...), которые присутствуют в data1. Требуется точное совпадение.

Все работает хорошо с grep -f data1 data2 data3 ..., пока элементы в data1 также не будут разделены нулями.

  1. Использование только новых строк - ok :

    $ cat data1
    1234
    abcd
    efgh
    5678
    $ cat data2
    1111
    oooo
    abcd
    5678
    $ grep -xFf data1 data2
    abcd
    5678
    
  2. data2 содержит элементы, разделенные нулем - ok при использовании -z:

    $ printf '1111\0oooo\0abcd\0005678' > data2
    $ grep -zxFf data1 data2 | xargs -0 printf '%s\n'
    abcd
    5678
    
  3. Теперь и data1, и data2 содержат элементы, разделенные нулем - fail . Кажется, что опция -z не применяется к файлу, указанному с -f:

    $ printf '1234\0abcd\0efgh\0005678' > data1
    $ grep -zxFf data1 data2 | xargs -0 printf '%s\n'
    
    $
    

Проблема в том, что мне нужны оба файла , чтобы иметь элементы с нулевым разделением. Очевидным обходным приемом может быть (например) старый добрый цикл while:

while IFS= read -rd '' line || [[ $line ]]; do
    if grep -zqxF "$line" data2; then
        printf '%s\n' "$line"
    fi
done < data1

Но так как у меня много файлов с большим количеством элементов, это будет мучительно медленно! Есть ли лучший подход (я не настаиваю на использовании grep)?

Ответы [ 2 ]

0 голосов
/ 28 августа 2018

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

grep имеет новую строку в качестве терминатора шаблона. Даже если вы используете -e pattern, новые строки в строке шаблона приведут к тому, что grep будет обрабатывать параметры как указывающие несколько шаблонов, а не один шаблон, содержащий символы новой строки.

Однако, если ваши шаблоны, разделенные NUL, не содержат символов новой строки, вы можете использовать Gnu xargs и sed для создания соответствующего grep вызова с -e аргументами командной строки:

sed -z 's/^/-e/' data | xargs -0 grep -zF data2 ...

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

Насколько я знаю, не существует обходного пути для шаблонов, которые могут содержать символы новой строки. grep -E и grep -F не распознают escape-последовательности ascii и будут молча создавать несколько шаблонов из шаблона, который содержит символ новой строки. grep -P (другое расширение Gnu, использующее регулярное выражение PCRE) будет правильно обрабатывать встроенные символы новой строки или символы ascii, но допускает только один шаблон.


Полные строки с NUL-завершенными совпадениями без сортировки

В случае, если вас интересуют только точные, полные совпадения строк (-Fx), вы можете использовать сценарий Gnu Awk вместо сортировки входных данных и шаблонов. Это может быть выигрыш для очень больших входов, которые не помещаются в памяти; сортировка по внешним временным файлам может быть довольно дорогой. Решение Awk использует хеш-таблицу, поэтому сортировка не требуется. (Опять же, это может не сработать на всех Awks, потому что оно основано на установке RS в NUL.)

awk -v RS=`\0` 'NR==FNR{p[$0] = 1; next;} $0 in p' data data2 ...
0 голосов
/ 28 августа 2018

Поскольку сохранение порядка не имеет значения, вы пытаетесь сопоставить точные строки, и у вас есть доступные инструменты GNU, вместо использования fgrep Я бы предложил comm -z.

$ printf '%s\0' 1111 oooo abcd 005678 >data2
$ printf '%s\0' 1234 abcd efgh 005678 >data
$ comm -z12 <(sort -uz <data) <(sort -uz <data2) | xargs -0 printf '%s\n'
005678
abcd

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

...