мой вопрос является продолжением вопроса, заданного давным-давно. Вопрос заключался в том, чтобы найти общие элементы в> 2 файлах в Linux при сопоставлении записей в определенных столбцах.
Вопрос был (я имею в виду этот пост: найти общие элементы в> 2 файлах)
У меня есть три файла, как показано ниже
файл1.txt
"aba" 0 0 1
"abc" 0 1
"abd" 1 1
"xxx" 0 0
файл2.txt
"xyz" 0 0
"aba" 0 0 0 1
"xxx" 0 0
"abc" 1 1
файл3.txt
"xyx" 0 0
"aba" 0 0
"xxx" 0 0 0 1
"abc" 1 1
Я хочу найти похожие элементы во всех трех файлах на основе первых двух столбцов.
Теперь я хочу не только найти похожие элементы из всех файлов, но и вывести соответствующие строки из всех файлов. Обратите внимание, что ни один из моих файлов не отсортирован.
Примечание. Я ищу, чтобы сопоставлять элементы в столбце 1 только из всех файлов и последовательно печатать соответствующие строки из файлов.
Итак, в этом примере мой желаемый результат будет:
"xxx" 0 0 0 0 0 0 1
"aba" 0 0 1 0 0 0 1 0 0
"abc" 0 1 1 1 1 1
где он печатает совпадающие элементы ($ 1) из файлов 1-3 последовательно.
Один пользователь предложил следующее решение:
awk '
FNR == NR {
arr[$1,$2] = 1
line[$1,$2] = line[$1,$2] ( line[$1,$2] ? SUBSEP : "" ) $0
next
}
FNR == 1 { delete found }
{ if ( arr[$1,$2] && ! found[$1,$2] ) { arr[$1,$2]++; found[$1,$2] = 1 } }
END {
num_files = ARGC -1
for ( key in arr ) {
if ( arr[key] < num_files ) { continue }
split( line[ key ], line_arr, SUBSEP )
for ( i = 1; i <= length( line_arr ); i++ ) {
printf "%s\n", line_arr[ i ]
}
}
}
' file1.txt file2.txt file3.txt
Однако это соответствует первым двум столбцам и печатает только всю строку из файла, который появляется первым в списке (здесь file1.txt)
Результат, который это дает:
"xxx" 0 0
"aba" 0 0
"aba" 0 0 1
Есть ли способ изменить этот скрипт, чтобы он печатал совпадающие строки из всех файлов. Мне нужно, чтобы строки отображались рядом в формате, указанном выше. Мой файл разделен табуляцией, поэтому хотелось бы, чтобы вывод также был разделен табуляцией. Еще одним важным моментом является то, что все файлы содержат одинаковое количество столбцов, но различаются количеством строк.
На самом деле в моем файле элементы уникальны. В этом примере аба присутствует дважды, поэтому может возникнуть путаница. Если хотите, можете предположить, что я сравниваю первые два столбца, а все элементы в столбце 1 уникальны. Спасибо. Однако во втором столбце есть дубликаты, но первый столбец имеет приоритет.
Более того, я думаю, что нет необходимости сравнивать элементы в столбце 2. Поскольку в моих файлах все значения столбца 1 уникальны, я могу просто сопоставить их между всеми файлами и отобразить строки из каждого файла, содержащие общие элементы.
Так что, abc тоже не должно появляться?
Да, abc должен появиться, если я сопоставляю только первый столбец. В приведенном примере он соответствует первым двум столбцам, поэтому abc не появляется. Меня интересует сопоставление столбца 1. Я внесу необходимые изменения в исходный пост.
Важен ли порядок выходных строк? Что определяет порядок?
Нет, порядок вывода не важен. В приведенном примере порядок определяется файлом, который находится первым в списке. Но здесь это не имеет значения.
@David: На самом деле в моем файле элементы уникальны. Пожалуйста, исправьте свои файлы примеров и выходные данные примеров, чтобы они отражали уникальные элементы. В противном случае ответы, которые вы получите, будут неправильными...
Я изменил свои входные файлы, чтобы избежать путаницы.
@David: Пожалуйста, также обновите вывод примера на основе этого
Данный:
$ head file?.txt
==> file1.txt <==
"aba" 0 0 1
"abc" 0 1
"abd" 1 1
"xxx" 0 0
==> file2.txt <==
"xyz" 0 0
"aba" 0 0 0 1
"xxx" 0 0 0 1
"abc" 1 1
==> file3.txt <==
"xyx" 0 0
"aba" 0 1 0
"xxx" 0 0 0 1
"abc" 1 1
Предполагая, что появление "aba"
дважды в файлах является опечаткой (из комментариев), вы можете сделать это:
$ awk '{cnt[$1]++
s = ""
for (i=2;i<=NF;i++) s=s OFS $i
seen[$1]= seen[$1] s}
END{for (e in seen) if (cnt[e]>1) print e, seen[e]}' file?.txt
Отпечатки:
"aba" 0 0 1 0 0 0 1 0 1 0
"abc" 0 1 1 1 1 1
"xxx" 0 0 0 0 0 1 0 0 0 1
Из комментариев.
Данный:
$ head file{1..3}.txt
==> file1.txt <==
"aba" 0 0 1
"abc" 0 1
"abd" 1 1
"xxx" 0 0
==> file2.txt <==
"xyz" 0 0
"aba" 0 0 0 1
"xxx" 0 0 0 1
"abc" 1 1
==> file3.txt <==
"xyx" 0 0
"xxx" 0 0 0 1
"abc" 1 1
(Примечание "aba"
удалено в файле 3...)
Вы можете использовать этот awk:
$ awk 'FNR==1 {fcnt++}
{cnt[$1]++
s = ""
for (i=2;i<=NF;i++) s=s OFS $i
seen[$1]= seen[$1] s}
END{for (e in seen) if (cnt[e]==fcnt) print e, seen[e]}' file{1..3}.txt
Отпечатки:
"abc" 0 1 1 1 1 1
"xxx" 0 0 0 0 0 1 0 0 0 1
Эй, спасибо за ответ. Однако при запуске вашего сценария awk я получаю в качестве вывода: 0 1 0 1 0, 1 1 1 1 1, 0 0 0 1 0 0 0 Запятые предназначены для разделителей строк. По какой-то причине я не могу отформатировать раздел комментариев в формат кода
Ваши файлы из Windows?
Я работаю на машине с Windows, используя сервер на базе Linux через MobaXterm.
Дополнительные переводы строки, вероятно, происходят из вашей среды. Они не исходят из сценария awk.
Проблема решена. Каким-то образом каждая из моих строк имеет невидимый ^M, прикрепленный к конечному символу, который вызывал проблему.
Не могли бы вы изменить сценарий так, чтобы он печатал только строки, если элемент IFF n найден во всех файлах? Ваш скрипт отлично работает, но он печатает строки из файлов, даже если элемент совпадает только в 2-х файлах. В примере, который вы разработали, скажем, если «abc» отсутствует в файле 3.txt, вывод вообще не должен содержать abc. Здесь он по-прежнему будет печатать строки abc из файла1 и файла2.
@ Дэвид, я не читал ваш вопрос, так как у вас уже есть принятый ответ, но похоже, что вы приняли ответ, который не делает то, что вы хотите, тем самым отговаривая кого-либо еще публиковать ответ, который может делать то, что вы хотите, и теперь надеюсь, что у того, кто опубликовал этот ответ, будет время / возможность изменить его, чтобы делать то, что вы хотите. Для будущих вопросов вы можете подождать, пока не получите 1 или несколько ответов, которые делают именно то, что вы хотите, прежде чем принять один из них.
@EdMorton: Честно говоря, он делает именно то, что он задал в вопросе. Если он хочет эту дополнительную функциональность, примеры и вопросы должны говорить об этом.
@dawg а, так это Вопрос-хамелеон, и они должны задать новый дополнительный вопрос.
@ЭдМортон: точно
@David: Насколько я понимаю, что вы ищете, я сделал эту модификацию.
Должен ли аба появляться дважды в ожидаемом результате?