Получить шаблоны в одном файле из другого, используя ack или awk или лучше, чем grep? - PullRequest
5 голосов
/ 30 марта 2012

Есть ли способ получить шаблоны в одном файле (список шаблонов) из другого файла, используя ack в качестве опции -f в grep? Я вижу, что в ack есть опция -f, но она отличается от -f в grep.

Возможно, пример даст вам лучшую идею. Предположим, у меня есть файл1:

file1:
a
c
e

И файл2:

file2:
a  1
b  2
c  3
d  4
e  5

И я хочу получить все шаблоны в файле1 из файла2, чтобы дать:

a  1
c  3
e  5

Может ли ack сделать это? Иначе, есть ли лучший способ справиться с заданием (например, awk или использование хэша), потому что у меня есть миллионы записей в обоих файлах, и мне действительно нужен эффективный способ завершения? Спасибо!

Ответы [ 5 ]

8 голосов
/ 30 марта 2012

Вот Perl-однострочник, который использует хеш для хранения набора требуемых ключей из file1 для O (1) (амортизированное время) поисков за итерацию по строкам file2.Таким образом, он будет выполняться за время O (m + n), где m - количество строк в вашем наборе ключей, а n - количество строк в тестируемом файле.

perl -ne'BEGIN{open K,shift@ARGV;chomp(@a=<K>);@hash{@a}=()}m/^(\p{alpha}+)\s/&&exists$hash{$1}&&print' tkeys file2

Набор ключей будет храниться в памяти, в то время как file2 тестируется строка за строкой с ключами.

Вот то же самое, используя параметр командной строки Perl -a:

perl -ane'BEGIN{open G,shift@ARGV;chomp(@a=<G>);@h{@a}=();}exists$h{$F[0]}&&print' tkeys file2

Вторая версия, вероятно, немного проще для глаз.;)

Одна вещь, которую вы должны здесь помнить, это то, что более вероятно, что вы связаны с IO, чем с процессором.Таким образом, цель должна состоять в том, чтобы минимизировать использование IO.Когда весь набор ключей поиска хранится в хэше, который предлагает O (1) амортизированных поисков.Преимущество этого решения по сравнению с другими решениями заключается в том, что некоторым (более медленным) решениям придется проходить через файл ключа (файл1) один раз для каждой строки файла2.Решением такого рода будет O (m * n), где m - размер вашего ключевого файла, а n - размер файла2.С другой стороны, этот хэш-подход обеспечивает время O (m + n).Это величина разницы.Это дает преимущества за счет исключения линейного поиска по набору ключей, а дополнительные преимущества - за счет считывания ключей с помощью ввода-вывода только один раз.

6 голосов
/ 30 марта 2012

Ну ладно, если мы перешли от комментариев к ответам ...; -)

Вот один строковый элемент awk, который делает то же самое, что и однострочный perl DavidO, но в awkAwk меньше и, возможно, меньше, чем Perl.Но есть несколько разных реализаций awk.Я понятия не имею, будет ли ваш работать лучше, чем другие, или Perl.Вам нужно будет тестировать.

awk 'NR==FNR{a[$0]=1;next} {n=0;for(i in a){if($0~i){n=1}}} n' file1 file2

Что это делает (должно) сделать?

Первая часть скрипта awk соответствует только строкам в file1 (гденомер записи в текущем файле равен общему количеству записей) и заполняет массив.Вторая часть (которая запускается в последующих файлах) проходит по каждому элементу в массиве и проверяет, можно ли использовать его в качестве регулярного выражения для соответствия текущей строке ввода.

Второй блок кода начинается с "n", который был установлен в 0 или 1 в предыдущем блоке.В awk «1» оценивается как истина, а отсутствующий блок фигурных скобок считается эквивалентным {print}, поэтому, если предыдущий блок обнаружил совпадение, этот будет печатать текущую строку.

Если file1 содержит строки вместо регулярных выражений, то вы можете изменить это для ускорения работы, заменив первое сравнение на if(index($0,i))....

Используйте с осторожностью.Ваш пробег может варьироваться.Создан на объекте, который может содержать орехи.

1 голос
/ 20 июня 2013

Вы можете преобразовать файл в регулярное выражение для подтверждения с помощью tr. Я использовал sed для удаления символа задней трубы.

ack "` tr '\ n' '|'

Обратите внимание, что для этого вам нужна пара процессов, поэтому решение awk, вероятно, более эффективно, но это довольно легко запомнить.

1 голос
/ 30 марта 2012

TXR может быть другим вариантом для удовлетворения ваших требований. Я слишком новичок, чтобы писать то, что вам нужно, но автор часто вносит свой вклад в StackOverflow. Хотя я уверен, что вы можете делать то, что вам нужно, с TXR, но я не уверен, что он будет работать лучше. Вам нужно проверить.

Стоит посмотреть, если вам интересен целый язык, посвященный сопоставлению с образцом. :)

1 голос
/ 30 марта 2012
nawk 'FNR==NR{a[$0];next}($1 in a)' file3 file4

испытываться:

pearl.384> cat file3
a
c
e
pearl.385> cat file4
a  1 
b  2 
c  3 
d  4 
e  5
pearl.386> nawk 'FNR==NR{a[$0];next}($1 in a)' file3 file4
a  1 
c  3 
e  5
pearl.387>
...