#shell #unix #awk
#оболочка #unix #awk
Вопрос:
Я хотел бы сравнить первые два столбца из двух файлов, если они совпадают, нужно напечатать yes, иначе no.
input.txt
123,apple,type1
123,apple,type2
456,orange,type1
6567,kiwi,type2
333,banana,type1
123,apple,type2
qualified.txt
123,apple,type4
6567,kiwi,type2
output.txt
123,apple,type1,yes
123,apple,type2,yes
456,orange,type1,no
6567,kiwi,type2,yes
333,banana,type1,no
123,apple,type2,yes
Я использовал приведенную ниже команду для разделения данных, а затем добавлю еще один столбец на основе результата.
Теперь input.txt имеет дубликат (1-й столбец), поэтому приведенный ниже метод не работает, кроме того, размер файла был огромным.
Можем ли мы получить output.txt в awk
одном лайнере?
comm -2 -3 input.txt qualified.txt
Комментарии:
1. Почему первые 2 столбца? Похоже, что первые 2 всегда сопряжены, так почему бы просто не сравнить 1 из них? Если они не всегда сопряжены (например, у вас может быть
123,apple
и9631,apple
), включите это в свой пример.
Ответ №1:
$ awk -F, 'NR==FNR {a[$1 FS $2];next} {print $0 FS (($1 FS $2) in a?"yes":"no")}' qual input
123,apple,type1,yes
123,apple,type2,yes
456,orange,type1,no
6567,kiwi,type2,yes
333,banana,type1,no
123,apple,type2,yes
Объяснено:
NR==FNR { # for the first file
a[$1 FS $2];next # aknowledge the existance of qualified 1st and 2nd field pairs
}
{
print $0 FS ($1 FS $2 in a?"yes":"no") # output input row and "yes" or "no"
} # depending on whether key found in array a
Нет необходимости переопределять OFS
, поскольку $0
он не изменяется и не перестраивается.
Ответ №2:
Вы можете использовать awk
логику для этого, как показано ниже. Не уверен, почему вы упоминаете однострочную команду awk.
awk -v FS="," -v OFS="," 'FNR==NR{map[$1]=$2;next} {if($1 in map == 0) {$0=$0FS"no"} else {$0=$0FS"yes"}}1' qualified.txt input.txt
123,apple,type1,yes
123,apple,type2,yes
456,orange,type1,no
6567,kiwi,type2,yes
333,banana,type1,no
123,apple,type2,yes
Логика
- Команда
FNR==NR
анализирует первый файлqualified.txt
и сохраняет записи в столбце1
и2
в первом файле, причем первый столбец является индексом. - Затем для каждой строки во 2-м файле
{if($1 in map == 0) {$0=$0FS"no"} else {$0=$0FS"yes"}}1
запись в столбце 1 не соответствует массиву, добавьтеno
строку иyes
в противном случае. -v FS="," -v OFS=","
предназначены для установки разделителей полей ввода и вывода
Комментарии:
1. Отсутствие пробела после
-v
делает ваш скрипт совершенно излишне специфичным для gawk. Имя массиваseen
идиоматически используется для представления набора, а не сопоставления. Используйтеmap
или аналогичный вместо этого для ясности, если вы создаете карту, но я не вижу, чтобы вы на самом деле ссылались на нее как на карту, просто заполняя ее как таковую, поэтому idk…2. @EdMorton: Спасибо за исправление, жаль, что я не знал об этом раньше 🙂
Ответ №3:
Похоже, все, что вам нужно, это:
awk 'BEGIN{FS=OFS=","} NR==FNR{a[$1];next} {print $0, ($1 in a ? "yes" : "no")}' qualified.txt output.txt