【问题标题】:Find common elements in a particular column >2 files and print the corresponding lines from each在特定列 >2 个文件中查找公共元素并打印每个文件中的相应行
【发布时间】:2021-04-03 22:07:32
【问题描述】:

我的问题是很久以前提出的问题的延伸。问题是在 linux 中的 >2 个文件中找到共同元素,匹配特定列中的条目。

问题是(我指的是这个帖子:find common elements in >2 files

我有如下三个文件

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 "%s\n", line_arr[ i ]
            } 
        } 
    }
' file1.txt file2.txt file3.txt

但是,这匹配前 2 列,并且仅打印列表中第一个出现的文件(此处为 file1.txt)中的整行

这给出的输出是:

"xxx" 0 0
"aba" 0 0 
"aba" 0 0 1

有没有办法修改这个脚本,以便打印所有文件中的匹配行。我需要以上述格式并排显示这些行。我的文件是制表符分隔的,因此也希望输出也以制表符分隔。另一个重要的一点是文件都包含相同的列数但不同的行数。

【问题讨论】:

  • aba 是否意味着在预期结果中出现两次?
  • 实际上在我的文件中元素是独一无二的。在此示例中,aba 出现了两次,因此可能会造成混淆。如果您愿意,可以假设我正在比较前两列,并且第 1 列中的元素都是唯一的。谢谢。然而,在第二列中有重复项,但第一列优先。
  • 此外,我认为没有必要比较第 2 列中的元素。由于在我的文件中,第 1 列的值都是唯一的,我可以在所有文件中匹配它们,并显示每个文件中的行包含通用元素的文件。
  • 那么 abc 不应该也出现吗?
  • 是的,如果我只匹配第一列,应该出现 abc。在给出的示例中,它匹配前两列,因此 abc 不会出现。我有兴趣匹配第 1 列。我将在原始帖子中进行必要的编辑。

标签: python unix awk


【解决方案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" 是一个错字(来自 cmets),您可以这样做:

$ 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 机器上工作,通过 MobaXterm 使用基于 Linux 的服务器
  • @dawg 啊,所以它是Chameleon Question,他们应该提出一个新的后续问题。
  • @EdMorton: 完全正确
猜你喜欢
  • 2013-05-31
  • 2020-06-13
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 2022-10-12
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
相关资源
最近更新 更多