bash - сравнить два столбца одного файла с одним столбцом второго файла и распечатать совпадения - PullRequest
2 голосов
/ 05 мая 2020

У меня есть два разных файла примерно по 1000 строк в каждом, которые структурированы следующим образом:

file1: (Имя; Фамилия; Адрес)

Mike;Tyson;First Street 2
Tom;Boyden;Second Street 6
Tom;Cruise;Third Street 9
Mike;Myers;Second Street 4

file2: (Имя Фамилия; Электронная почта; ID) ИЛИ (Фамилия Имя; Электронная почта; ID)

Mike Tyson;mike@tyson.com;45753
Cruise Tom;tom@cruise.com;23562
Jennifer Lopez;jennifer@lopez.com;92746
Brady Tom;tom@brady.com;27583

Я хотел бы сравнить первые два столбца файла1 с ВСЕМ первым столбцом файла2. Если обе записи файла file1 присутствуют в первом столбце файла file2 (в любом порядке), я хочу напечатать соответствующую строку файла file1. Затем найдите вторую строку файла1 и снова сравните ее со всем столбцом файла2 и т. Д.

В файле2 порядок может быть (Имя Фамилия) ИЛИ (Фамилия Имя), и я хочу чтобы напечатать соответствующую строку в обоих случаях.

Ожидаемый результат:

Mike;Tyson;First Street 2
Tom;Cruise;Third Street 9

Я доволен решением, использующим awk, grep или что-то еще.

I ' я пробовал решить аналогичный вопрос, но результат пуст:

awk -F';' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file1 file2

Спасибо

Ответы [ 2 ]

4 голосов
/ 05 мая 2020
$ awk -F'[ ;]' '
    { key=($1 > $2 ? $1 FS $2 : $2 FS $1) }
    NR==FNR { a[key]; next }
    key in a
' file1 file2
Mike Tyson;mike@tyson.com;45753
Cruise Tom;tom@cruise.com;23562

Вышеупомянутый использует общий, идиоматический c подход к генерации согласованного ключа независимо от порядка, в котором появляются ключевые компоненты, путем сортировки компонентов перед их объединением для создания значения ключа. Когда есть только 2 компонента, как в этом случае, простое сравнение - единственная необходимая сортировка.

Вот почему сортировка компонентов ключа - правильный подход. Представьте, что у вас есть 3 компонента, 1, 2 и 3 доллара, а не только 2. При подходе к тестированию каждой комбинации вам нужно следующее:

NR==FNR { a[$1,$2,$3]; next }
($1,$2,$3) in a || ($1,$3,$2) in a || ($2,$1,$3) in a ||
($2,$3,$1) in a || ($3,$1,$2) in a || ($3,$2,$1) in a

Попробуйте написать это условие для 1–4 долларов :-).

Напротив, если вы используете подход сортировки компонентов, которые вам нужны (с использованием GNU awk для встроенных функций сортировки для удобства), что НАМНОГО труднее ошибиться (например, если забыть комбинацию при сравнении):

NR==FNR {
    split($1 FS $2 FS $3,flds)
    asort(flds)
    key = flds[1]
    for (i=2; i in flds; i++) {
        key = key FS flds[i]
    }
    a[key]
    next
}
key in a

А теперь представьте, хотите ли вы использовать от 1 до 10 долларов в любом порядке. Подход «тестируйте каждую комбинацию компонентов» становится невыносимым кошмаром, в то время как подход «отсортируйте компоненты для создания ключа» просто означает тривиальное добавление полей в список в первом аргументе split ().

2 голосов
/ 05 мая 2020

Не могли бы вы попробовать следующее.

awk '
FNR==NR{
  array[$1,$2]
  next
}
(($1,$2) in array) || (($2,$1) in array)
' FS="[ ;]"  Input_file2  FS=";" Input_file1

Пояснение: Добавление подробного объяснения вышеуказанного решения.

awk '                                       ##Starting awk program from here.
FNR==NR{                                    ##Checking condition if FNR==NR which will be true when file2 is being read.
  array[$1,$2]                              ##Creating array with index $1,$2 here.
  next                                      ##next will skip all further statement from here.
}
(($1,$2) in array) || (($2,$1) in array)    ##Checking condition if $1,$2 OR $2,$1 is present in array then it will print the line from Input_file1.
' FS="[ ;]"  file2  FS=";" file1            ##Set field separator space or semi-colon for file2 AND set field separator as ; for file1 here.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...