field-names.txt 包含字段名称列表:
AB_CODE
ACFT_CODE
AC_TYPE
ADD_INFO
AKA
ALT
ALT1_DESC
ALT2_DESC
ALT3_DESC
对于每个字段名称,我想打印第一行包含此字段名称的文件(以空格分隔的字段列表)。以下是我尝试的:
在bash
命令行我输入了以下内容:
cat field-names.txt | awk 'BEGIN { getline fieldname; print fieldname }
NR == 1 && $0 ~ /fieldname/ { print FILENAME }' **/*.TXT
这会产生错误的结果。正确的做法是什么?
这个
awk
解决方案应该适合你:首先,我们在 的第一个块中的
|
每一行之间构建一个正则表达式。然后我们使用该正则表达式匹配使用该正则表达式的每个第一行。我们在每个第一行和正则表达式的前缀和后缀上空格,以确保我们只匹配整个单词而不是部分单词。field-names.txt
FNR == NR
为了优化,我们可以这样做,只构建一次完整的正则表达式:
(afre 的计算由@Ed Morton 的评论提供)
我们在开始时花一次时间来计算所关注的所有字段中的任何一个的正则表达式,
以便主“循环”可以以最大速度运行。
由于我们只查看第一行,查找完毕后,我们会无条件使用 nextfile切换到下一个输入文件,无论是否匹配。
选择哪种解决方案?
因此,与@anubhava 的解决方案(我也喜欢并投票赞成:对于我的前两个要点,选择哪种解决方案取决于个人喜好)的区别在于:
^
和$
作为第一个或最后一个字段进行匹配,但我经常也使用额外的空格技巧
进一步优化
请注意,根据 awk 的实现,
$0 ~ afre
可能会在每一行重新编译正则表达式(因为它是一个变量,它可以变化,因此如果 awk 想要缓存正则表达式的编译版本,它必须检查它没有改变)。当你通过 shell 运行它时,你可以强制它使用固定的正则表达式(更容易优化)(不可否认的是可读性较差):
假设您想要将字段名称的映射输出到它们出现的文件中,然后使用任何 awk(未经测试):
无论您的目标文件名是否包含正则表达式元字符,这都可以起作用
.
。更改
"* Not found *"
为其他字符串或执行其他任何您喜欢的操作来处理任何输入文件中不存在的目标字段。如果您想在字段名称和每个关联文件名之间使用除空白字符之外的其他分隔符,只需将其设置OFS
为您喜欢的任何字符串即可。另一种方法是不使用正则表达式,因为看起来字段名称列表只是简单的字符串:
此代码还接受行首和行末的字段名称。