我的问题是很久以前提出的问题的延伸。问题是在>linux中的2个文件,根据特定列中的匹配条目。
问题是(我指的是这篇文章:在>2个文件中找到常见元素(
我有三个文件,如下所示
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
"abc" 1 1
file3.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-3的匹配元素($1(。
一位用户为此提供了以下解决方案:
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 "%sn", line_arr[ i ]
}
}
}
' file1.txt file2.txt file3.txt
但是,这与前2列匹配,并且只打印列表中第一个出现的文件(此处为file1.txt(的整行
它给出的输出是:
"xxx" 0 0
"aba" 0 0
"aba" 0 0 1
有没有办法修改这个脚本,让它打印所有文件中的匹配行。我需要线条并排显示,格式如上所述。我的文件是制表符分隔的,所以我希望输出也是制表符分隔。另一个重要的点是,所有文件都包含相同的列数,但不同的行数。
给定:
$ 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
(注意文件3中删除了"aba"
…(
你可以使用这个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