Awk 在>;2个文件

Awk 在>;2个文件,awk,compare,Awk,Compare,我有三个文件,如下所示 file1.txt "aba" 0 0 "aba" 0 0 1 "abc" 0 1 "abd" 1 1 "xxx" 0 0 file2.txt "xyz" 0 0 "aba" 0 0 0 0 "aba" 0 0 0 1 "xxx" 0 0 "abc" 1 1 file3.txt "xyx" 0 0 "aba" 0 0 "aba" 0 1 0 "xxx" 0 0 0 1 "abc" 1 1 我想根据前两列在所有三个文件中找到相似的元素。为了在两个文件中找到相似的

我有三个文件,如下所示

file1.txt

"aba" 0 0 
"aba" 0 0 1
"abc" 0 1
"abd" 1 1 
"xxx" 0 0
file2.txt

"xyz" 0 0
"aba" 0 0 0 0
"aba" 0 0 0 1
"xxx" 0 0
"abc" 1 1
file3.txt

"xyx" 0 0
"aba" 0 0 
"aba" 0 1 0
"xxx" 0 0 0 1
"abc" 1 1
我想根据前两列在所有三个文件中找到相似的元素。为了在两个文件中找到相似的元素,我使用了

awk 'FNR==NR{a[$1,$2]++;next}a[$1,$2]' file1.txt file2.txt 
但是,当输入文件超过2个时,我们如何在所有文件中找到相似的元素? 有人能帮忙吗

对于当前的awk解决方案,输出将忽略重复的键列,并将输出作为

"xxx" 0 0
如果我们假设输出来自file1.txt,则预期输出为:

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

i、 e它还应该获得具有重复键列的行。

尝试以下针对N文件的通用解决方案。它将第一个文件的数据保存在值为
1
的散列中,对于下一个文件的每次命中,该值都会递增。最后,我比较每个键的值是否与处理的文件数相同,并只打印匹配的文件

awk '
    FNR == NR { arr[$1,$2] = 1; next }
    { if ( arr[$1,$2] ) { arr[$1,$2]++ } }
    END { 
        for ( key in arr ) {
            if ( arr[key] != ARGC - 1 ) { continue }
            split( key, key_arr, SUBSEP )
            printf "%s %s\n", key_arr[1], key_arr[2] 
        } 
    }
' file{1..3}
它产生:

"xxx" 0
"aba" 0

编辑以添加打印整行的版本(请参见注释)。我在保存行的位置添加了另一个具有相同键的数组,并在
printf
函数中使用它。我对旧代码进行了注释

awk '
    ##FNR == NR { arr[$1,$2] = 1; next }
    FNR == NR { arr[$1,$2] = 1; line[$1,$2] = $0; next }
    { if ( arr[$1,$2] ) { arr[$1,$2]++ } }
    END { 
        for ( key in arr ) {
            if ( arr[key] != ARGC - 1 ) { continue }
            ##split( key, key_arr, SUBSEP )
            ##printf "%s %s\n", key_arr[1], key_arr[2] 
            printf "%s\n", line[ key ] 
        } 
    }
' file{1..3}

新建编辑(请参阅注释)以添加一个版本,该版本使用相同的键处理多行。基本上,我加入所有条目,而不是只保存一个,将
行[$1,$2]=$0
更改为
行[$1,$2]=行[$1,$2](行[$1,$2]?子集:)$0
。在打印时,我使用分隔符(
subsp
变量)进行反向拆分,并打印每个条目

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 ]
            } 
        } 
    }
' file{1..3}

此python脚本将列出所有文件中的公用行:

import sys
i,l = 0,[]
for files in sys.argv[1:]:
  l.append(set())
  for line in open(files): l[i].add(" ".join(line.split()[0:2]))
  i+=1
commonFields =  reduce(lambda s1, s2: s1 & s2, l)
for files in sys.argv[1:]:
  print "Common lines in ",files
  for line in open(files):
    for fields in commonFields:
      if fields in line:
        print line,
        break

用法:python script.py file1 file2 file3…

对于三个文件,您只需要:

awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt file2.txt file3.txt
FNR==NR
块仅对参数列表中的第一个文件返回true。此块中的
next
语句强制跳过代码的剩余部分。因此,中的
($1,$2)将对参数列表中除第一个文件以外的所有文件执行。要以现有方式处理更多文件,只需列出它们


如果您需要在命令行上使用更强大的globbing,请使用
extglob
。您可以使用
shopt-s extglob
打开它,然后使用
shopt-u extglob
关闭它。例如:

awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt !(file1.txt)
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt $(find /path/to/files -type f -name "*[23].txt")
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt file{2,3}.txt

如果文件很难找到,请使用
find
。例如:

awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt !(file1.txt)
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt $(find /path/to/files -type f -name "*[23].txt")
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt file{2,3}.txt

我假设您正在查找“N”文件的全局范围。例如:

awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt !(file1.txt)
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt $(find /path/to/files -type f -name "*[23].txt")
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt file{2,3}.txt

谢谢这里我提到了3个文件,但一般来说,我会有n个文件。我们怎样才能把它推广到nfiles@user1779730:请看上面的评论。HTH@user1779730:到底是什么不起作用?我已经测试了代码,但是如果您需要的输出与您在问题中描述的不同,您需要更具体一些。谢谢代码。如果是awk,对我会更有帮助script@user1779730:使用
find
选择所有要处理的文件,如:
awk'…'$(find/your/dir-maxdepth 1-type f-name'*your_pattern*'''-print)
或任何您需要的选择。@user1779730:我不明白您的意思。这不是一个
awk
问题,它决定了您要处理哪些文件。您想要自动确定文件的数量,但是,基于什么?代码应该在目录中存在的任何数量的模式*.txt文件上运行HI,上面的代码只输出两个键列。如果键列相同,是否可以修改它以从其中一个文件中获取所有列?i、 e在上面的示例中,输出应该是“xxx”0和“aba”0 0。感谢它按预期工作。我怀疑,如果每个文件中的列数不相等,那么相同的代码是否可以正常工作?