Awk 查找文本文件中多行的公共元素
假设File.txt如下所示:Awk 查找文本文件中多行的公共元素,awk,text-processing,Awk,Text Processing,假设File.txt如下所示: A1 B C D E F C H C J A2 F B D J C F T Y U I B C N J Y 我需要的是检查以模式^A开头的行,然后查找从$2到行尾的元素。然后我需要在以这些元素开始的行中找到公共元素。以下是File.txt的输出: A1 C J A2 Y 或 输出中公共元素(如J和C)的顺序无关紧要 p.S.Awk是首选。这有点难看,我觉得它应该可以以更干净的方式实现,但它至少对样本数据有效 /^A/ { amap[$1]=NF
A1 B C D
E F C H
C J
A2 F B
D J C
F T Y U I
B C N J Y
我需要的是检查以模式^A开头的行,然后查找从$2到行尾的元素。然后我需要在以这些元素开始的行中找到公共元素。以下是File.txt的输出:
A1 C J
A2 Y
或
输出中公共元素(如J和C)的顺序无关紧要
p.S.Awk是首选。这有点难看,我觉得它应该可以以更干净的方式实现,但它至少对样本数据有效
/^A/ {
amap[$1]=NF - 1
for (i=2; i<=NF; i++) {
rmap[$i]=rmap[$i] (rmap[$i]?SUBSEP:"") $1
}
next
}
$1 in rmap {
split(rmap[$1], a, SUBSEP)
for (f in a) {
for (i=1; i<=NF; i++) {
afmap[a[f],$i]++
}
}
}
END {
for (af in afmap) {
split(af, a, SUBSEP)
if (afmap[af] == amap[a[1]]) {
o[a[1]]=o[a[1]] (o[a[1]]?" ":"") a[2]
}
}
for (f in o) {
print f, o[f]
}
}
这有点难看,我觉得它应该以一种更干净的方式来实现,但它至少对样本数据有效
/^A/ {
amap[$1]=NF - 1
for (i=2; i<=NF; i++) {
rmap[$i]=rmap[$i] (rmap[$i]?SUBSEP:"") $1
}
next
}
$1 in rmap {
split(rmap[$1], a, SUBSEP)
for (f in a) {
for (i=1; i<=NF; i++) {
afmap[a[f],$i]++
}
}
}
END {
for (af in afmap) {
split(af, a, SUBSEP)
if (afmap[af] == amap[a[1]]) {
o[a[1]]=o[a[1]] (o[a[1]]?" ":"") a[2]
}
}
for (f in o) {
print f, o[f]
}
}
对真实二维阵列使用GNU awk并删除阵列和长度阵列:
$ cat tst.awk
{ for (i=1;i<=NF;i++) children[$1][$i] }
/^A/{ parents[$1]; delete children[$1][$1] }
END {
for (parent in parents) {
delete count
printf "%s", parent
for (child in children[parent])
for (grandchild in children[child])
if (++count[grandchild] == length(children[parent]))
printf " %s", grandchild
print ""
}
}
$ awk -f tst.awk file
A1 C J
A2 Y
它的工作原理是检查非A行中任何字段的出现次数是否与A行中第二个+字段的出现次数相匹配,因为这表明它在任何情况下都会出现。使用GNU awk进行真正的2D数组并删除数组和长度数组:
$ cat tst.awk
{ for (i=1;i<=NF;i++) children[$1][$i] }
/^A/{ parents[$1]; delete children[$1][$1] }
END {
for (parent in parents) {
delete count
printf "%s", parent
for (child in children[parent])
for (grandchild in children[child])
if (++count[grandchild] == length(children[parent]))
printf " %s", grandchild
print ""
}
}
$ awk -f tst.awk file
A1 C J
A2 Y
它的工作原理是检查非A行中任何字段的出现次数是否与A行中第二个+字段的出现次数相匹配,因为这表明它在任何情况下都会出现。不清楚您的意思。还有,到目前为止你尝试了什么?有一个到目前为止,你应该知道如何开始:对于每一个A*行,你要打印出所有元素之间的所有元素之间的共同点,从一个元素等于A *行的元素开始。完成后我会把它贴在这里。为什么C会出现在A1输出线上?所需行的初始字段是否计数?不清楚您的意思。还有,到目前为止你尝试了什么?有一个到目前为止,你应该知道如何开始:对于每一个A*行,你要打印出所有元素之间的所有元素之间的共同点,从一个元素等于A *行的元素开始。完成后我会把它贴在这里。为什么C会出现在A1输出线上?所需行的初始字段是否算数?如果我想从另一个文件中获取孙辈,该怎么办?我的意思是,如果我们从文件1中记录父母和他们的孩子,然后在文件B中查找孙子女,会怎么样?我已经尝试通过在第一行添加FNR==NR来修改您的代码,并且;下一个在第二行的儿童[$1][$1]之后。我还补充说{对于i=1;我不会更改任何内容,它将按原样工作,因为该脚本中没有任何内容关心您有多少个单独的输入文件。只需将您喜欢的任何文件添加到参数列表awk-f tst.awk file1 file2 file3…如果不起作用,请更新您的问题,以显示一些示例输入和预期输出,并澄清您的新要求ents.@Ed Morton:非常感谢。我可以编辑您的程序来调整我的问题的要求。谢谢您的关注。您的编程风格是学习awk时可以遵循的一个很好的示例。如果我想从另一个文件中获取孙辈呢?我的意思是如果我们从文件1中记录家长及其子女,然后查找gra呢文件B中的ndchildren?我已经尝试修改您的代码,在第一行添加FNR==NR,在第二行的children[$1][$1]之后添加;next;。我还添加了{对于i=1;我不会更改任何内容,它将按原样工作,因为该脚本中没有任何内容关心您有多少个单独的输入文件。只需将您喜欢的任何文件添加到参数列表awk-f tst.awk file1 file2 file3…如果不起作用,请更新您的问题,以显示一些示例输入和预期输出,并澄清您的新要求艾德·莫顿:非常感谢。我可以编辑你的程序来调整我的问题的要求。谢谢你的关注。你的编程风格是学习awk的一个很好的范例。