我有一个文本文件,如下所示:
Doc_A 123 abc
Doc_A 456 def
Doc_A 789 ghi
Doc_B 123 abc
Doc_B 456 def
Doc_C 123 abc
Doc_C 456 def
Doc_C 789 ghi
Doc_C 101 jkl
以及参考文件
Doc_A
Doc_B
Doc_C
Doc_D
Doc_E
Doc_F
我想从文本文件中提取与参考文件中的名称匹配的第一行并打印该行,如果没有匹配则打印某个固定模式,如下所示:
Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20
我可以使用 awk 如下所示来打印匹配模式。我如何根据我的要求以某种固定方式打印找不到的图案?
awk 'FNR == NR { a[$1] = 0; } FNR != NR { for (i in a) if ($0 ~ i && a[i]++ == 0) { print $0; break; } }' \ref.txt file.txt
答案1
在匹配条目时从查找数组中删除条目,然后打印末尾剩下的内容怎么样?
$ awk 'NR==FNR {a[$1]; next}
$1 in a {print; delete a[$1]}
END {for (i in a) print i, "10 20"}
' ref.txt file.txt
Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20
(请注意,awk 不保证数组遍历的顺序 - 如果这是一个问题。)
解释
同时NR==FNR
,我们正在处理第一个命名文件 ( ref.txt
):我们创建一个数组条目,以其第一个(在本例中为唯一)字段作为索引,然后移动到记录next
。我们不需要为数组元素赋值。
否则,我们正在处理第二个命名文件 ( file.txt
)。我们检查它的第一列是否与我们从参考文件构造的数组中匹配,如果匹配则a
打印记录。$0
然后我们删除该条目。
删除有两个目的:它“唯一化”匹配,因为下次我们测试$1 in a
相同的时$1
,答案将为 false。这也意味着在file.txt
处理完 的所有行之后,中的任何剩余元素a
尚未匹配 - 我们可以在END
块中以“固定”格式打印这些元素。
答案2
您的任务需要 awk 吗? grep
也可以使用。
您的文件似乎是用空格分隔的。下面的解决方案基于这样的假设:参考文件中的固定模式永远不会包含空格。
令文本文件为file.txt
.令参考文件为ref.txt
.
$ for P in $(cat ref.txt); do grep -m1 "^$P[[:blank:]]" file.txt || printf "%s 10 20\n" "$P"; done
Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20
答案3
您可以通过多种方式做到这一点,例如:
awk '
NR == FNR && !($1 in a){a[$1]=$0}
NR != FNR{print ($1 in a) ? a[$1] : $1" 10 20"}
' inp ref.txt
perl -lane '
$h{$F[0]} = $_ unless exists $h{$F[0]}}{
while ( <STDIN> ) {
chomp;
print(exists $h{$_} ? $h{$_} : qq<$_ 10 20>);
}
' inp < ref.txt
while IFS= read -r a
do
grep -m1 -F -- "$a" inp || echo "$a 10 20"
done < ref.txt
结果:
Doc_A 123 abc
Doc_B 123 abc
Doc_C 123 abc
Doc_D 10 20
Doc_E 10 20
Doc_F 10 20