如何仅从文件中提取匹配每个模式的第一行?

时间:2018-05-09 23:58:06

标签: awk sed grep

我有一个看起来像

的文本文件
Line_A 123
Line_A 456
Line_A 789
Line_B 123
Line_B 456
Line_B 789
Line_C 123
Line_C 456
Line_C 789

一个看起来像这样的参考文件:

 Line_A
 Line_B
 Line_C

我想从文本文件中提取与引用文件中的每个名称匹配的第一行,如下所示:

Line_A 123
Line_B 123
Line_C 123

到目前为止,我只能从第一场比赛获得第一行:

grep -A1 -w -f  reference.txt -m 1 file.txt

也许我需要一个for循环? TIA

3 个答案:

答案 0 :(得分:2)

另一个return CompareStr(k1->mValue, k2->mValue);

awk

将引用保留在一个集合中,当在文件中看到打印行并删除引用时,只会打印第一个实例。

答案 1 :(得分:1)

只要您在参数列表中首先列出参考文件,就可以在文件中单次传递,然后在Awk中执行此操作:

awk 'FNR == NR { name[$1] = 0; }
     FNR != NR { for (i in name) if ($0 ~ i && name[i]++ == 0) { print $0; break; } }' \
    reference.txt file.txt

使用样本输入,可以得到所需的输出。

这是Awk中相当标准的技术。您使用FNR == NR条件读取第一个文件(文件行号等于总行号;仅对第一个文件中的行使用)并保存适当的信息供以后使用。通常,人们在第一行使用next;有用。这意味着他们可以避免 FNR != NR条件 - 我喜欢对称性。

处理第二个及后续文件时,检查从第一个文件读取的每个名称是否与一行匹配,并且之前没有打印过该名称,如果尚未处理,则打印该行。如果当前名称匹配,则中断避免检查其他名称。

这是许多人写命令的方式;它也有效。

awk 'FNR == NR { name[$1] = 0; next }
     { for (i in name) if ($0 ~ i && name[i]++ == 0) { print $0; break; } }' \
    reference.txt file.txt

这里的代码的两个版本都在行中的任何地方查找名称;如果您严格要匹配第二个(或后续)文件的$1,则可以更改条件(实际上,简化它们)。并且karakfa shows在匹配时删除匹配(而不是递增计数器),这对性能更好,因为您不必继续匹配不再相关的匹配。但是,此处显示的代码更容易适应显示给定名称的第二个,第三个或最后一个条目(处理第二个或第三个涉及将0更改为1或2;处理'last'需要更多实质性更改)。

答案 2 :(得分:1)

又一个awk:

$ awk 'a[$1]++==1' ref file
Line_A 123
Line_B 123
Line_C 123

按上述顺序读取这两个文件,计算第一列中的每个字符串,并在第二次看到时打印。如果file中的字符串不在reference中,则会失败。在这种情况下,使用其他解决方案之一。