File 1:
Connect|20130320000023|UTC|PPP|[email protected]|[email protected]|0BCBE578|
File 2:
Connect|20130320000023|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Мне нужно найти совпадающие записи в Файле 1 и Файле 2 в столбце 5. Поэтому из вышесказанного мне нужно вернуть в выводе:
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Большое спасибо,
решение1
Метод №1: grep и awk
Для этого можно использовать этот фрагмент:
$ grep -f <(awk -F '|' '{print $5}' file1) file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Подробности
Бит, который использует, awk
анализирует первый файл, file1
вытаскивая все 5-е столбцы. Затем эти значения используются как список для grep
, который выведет все строки во 2-м файле, содержащие совпадение.
Предостережения относительно этого метода
Этот метод будет соответствовать любому вхождению 5-го столбца file1
из file2
.
Метод №2: Просто awk
Другой подход, который использовался на сайте в прошлом, заключается в использовании awk
возможности FNR. Это то, где awk
будет выполнена итерация по 2 файлам, прохождение второго файла построчно для каждой строки в первом.
Такой подход сделает это. Поместите следующее в файл cmds.awk
:
FNR == NR {
f1[$5] = $5
next
}
{ if ($5 == f1[$5]) print $0; }
Затем вы можете запустить это следующим образом:
$ awk -F '|' -f cmds.awk file1 file2
ПРИМЕЧАНИЕ:Вместо этого можно было бы использовать такой awk
шаблон:
FNR == NR {
f1[$5] = $5
next
}
{ if ($5 in f1) print $0; }
Пример
$ awk -F '|' -f s.awk file1 file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
Предостережения относительно этого метода
Этот подход может обрабатывать только один экземпляр каждого адреса электронной почты из file1
. Так что если есть 2 строки, которые имеют одинаковое значение для 5-го столбца, это не сможет различить их. Это кажется приемлемым, учитывая ваши требования в OP.
Присоединиться и отсортировать
Вы также можете сделать это с помощью join
и sort
.
$ join -t '|' -j 5 <(sort -k5,5 file2) <(sort -k5,5 file1) | sed 's/||.*//'
Это будет использовать разделитель |
и объединять отсортированные файлы в 5-м столбце. Этот подход печатает совпадения из обоих file1
и file2
, поэтому мы используем sed
, чтобы отсечь 2-е совпадение с конца.
Пример
$ join -t '|' -j 5 <(sort -k5,5 file2) <(sort -k5,5 file1) | sed 's/||.*//'
[email protected]|Connect|20130320000025|UTC|PPP|[email protected]|0BCBE578
решение2
Я бы сделал все это на Perl:
$ perl -F'\|' -ane '$k{$F[4]}++; print if $k{$F[4]}>1' file1 file2
Connect|20130320000025|UTC|PPP|[email protected]|[email protected]|0BCBE578|
-a
активирует автоматическое разбиение полей на массив@F
.-F'\|'
устанавливает разделитель полей-a
для|
.- Для каждой обработанной строки сохраните 5-е поле (индексы массива начинаются с
0
в Perl) как хэш-ключ ($k{$F[4]}++
и увеличьте его значение на единицу. При втором появлении поля это значение будет равно 2. - Скрипт обработает каждую строку обоих файлов (
file1
предыдущуюfile2
) и выведет строку, если пятое поле уже встречалось ранее, т.е. если$k{$F[4]}
оно больше единицы.
Это предполагает, что пятый столбец не повторяется в пределахтакой жефайл. Если это не так и некоторые столбцы могут дублироваться в одном файле, используйте это:
perl -e 'open(A,"$ARGV[0]"); while(<A>){@F=split(/\|/);$k{$F[4]}++;}
open(B,"$ARGV[1]"); while(<B>){@F=split(/\|/); print if $k{$F[4]}
}' file1 file2
решение3
Если размеры файлов сопоставимы, оптимальным решением будетsort
оба файла по интересующему вас столбцу, а затемjoin
их по этому столбцу. Если размеры файлов N
и M
тогда асимптотическое время выполнения O(N*log(N)+M*log(M))
.
Если один из файлов намного меньше другого, то O(N*M)
решение в других ответах лучше.