解释

解释

我有一个文本文件,如下所示:

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

相关内容