我有三个文件,如下所示
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
即它也应该获得具有重复键列的行。
答案 0 :(得分:3)
尝试以下针对 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}
NEW EDIT (请参阅注释)添加处理具有相同键的多行的版本。基本上,我加入所有条目,而只保存一个,将line[$1,$2] = $0
更改为line[$1,$2] = line[$1,$2] ( line[$1,$2] ? SUBSEP : "" ) $0
。在打印时,我使用分隔符(SUBSEP
变量)进行反向拆分并打印每个条目。
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}
对于有问题的新数据,它会产生:
"xxx" 0 0
"aba" 0 0
"aba" 0 0 1
答案 1 :(得分:1)
这个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 ...
答案 2 :(得分:1)
对于三个文件,您只需要:
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt file2.txt file3.txt
FNR==NR
块仅对参数列表中的第一个文件返回true。此块中的next
语句强制跳过代码的剩余部分。因此,对参数列表中除第一个文件之外的所有文件执行($1,$2) in a
。要以您拥有的方式处理更多文件,您只需列出它们即可。
如果在命令行上需要更强大的globbing,请使用extglob
。您可以使用shopt -s extglob
打开它,然后使用shopt -u extglob
将其关闭。例如:
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt !(file1.txt)
如果您很难找到文件,请使用find
。例如:
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt $(find /path/to/files -type f -name "*[23].txt")
我假设您正在寻找'N'文件的全局范围。例如:
awk 'FNR==NR { a[$1,$2]; next} ($1,$2) in a' file1.txt file{2,3}.txt