如何在 awk 中使用一个文件,其中一个文件作为输入文件,一个文件作为搜索项
how to use a file in awk with one filed as input file and one as searchterm
Hello World(我的第一个问题:)
我有一个包含两个字段的文件。
我希望awk
使用一个字段作为搜索另一个字段的输入文件。
假设输入文件看起来像:
CONFIG_file123;configelement_ABC
CONFIG_file124;configelement_XYZ
现在我希望 awk
读取字段 1 (CONFIG_file123
) 并将其用作输入文件,在其中搜索字段 2 (configelement_ABC
) 输出然后继续到输入文件中的下一行。
像这样:
awk 'BEGIN{ RS = "\n"; ORS="\n" } {if ([=11=] ~ /configelement_ABC/) { print FILENAME ";" [=11=] }}' CONFIG_file123
非常感谢您!
如果这有帮助:
CONFIG_file123
configelement_ABA Data1 Data2 Data3
configelement_ABB Data1 Data2
configelement_ABC Data1
configelement_ABD Data1 Data2 Data3
configelement_XYW Data1 Data2
configelement_XYX Data1 Data2 Data3
configelement_XYY Data1
configelement_XYZ Data1 Data2 Data3
CONFIG_file124
configelement_ABA Data1 Data2 Data3
configelement_ABB Data1 Data2
configelement_ABC Data1 Data2
configelement_ABD Data1 Data2 Data3
configelement_XYW Data1 Data2
configelement_XYX Data1 Data2 Data3
configelement_XYY Data1 Data2
configelement_XYZ Data1 Data2
Output
CONFIG_file123;configelement_ABC Data1
CONFIG_file124;configelement_XYZ Data1 Data2
为此使用 awk
,虽然可能可行,但有点超出范围。您可以使用 bash
循环,而 grep
:
while IFS=';' read -r file string; do grep -F "$string" "$file"; done < list.txt
当然,它假定您的文件名或搜索字符串中没有 ;
。但是如果你有一些,你的问题将是未明确说明的:两个字段之间的真正分隔在哪里,而不是一个 ;
?
awk -F\; '{
config_file =
search_term =
while ((getline < config_file) > 0) {
if ([=10=] ~ search_term) {
print [=10=]
break
}
}
}' input_file
这将处理一个文件名 input_file
,它应该有两个字段,用分号分隔。它将每条记录中的第一个字段作为配置文件,第二个字段作为要搜索的词。
使用 getline
从 config_file 读取到 $0(它将被拆分为正常记录)。 while 循环将读取配置文件中的每一行并将每一行与搜索词进行比较。如果找到搜索词,它将打印出来并停止搜索。 (如果要打印匹配的每一行,请删除 break 语句。)
测试中使用的示例输入和配置文件:
$ cat input_file
CONFIG_file123;configelement_ABC Data1
CONFIG_file123;configelement_XYZ Data1 Data2 Data3
CONFIG_file124;configelement_XYZ Data1 Data2
$ cat CONFIG_file123
configelement_ABA Data1 Data2 Data3
configelement_ABB Data1 Data2
configelement_ABC Data1
configelement_ABD Data1 Data2 Data3
configelement_XYW Data1 Data2
configelement_XYX Data1 Data2 Data3
configelement_XYY Data1
configelement_XYZ Data1 Data2 Data3
$ cat CONFIG_file124
configelement_ABA Data1 Data2 Data3
configelement_ABB Data1 Data2
configelement_ABC Data1 Data2
configelement_ABD Data1 Data2 Data3
configelement_XYW Data1 Data2
configelement_XYX Data1 Data2 Data3
configelement_XYY Data1 Data2
configelement_XYZ Data1 Data2
输出:
configelement_ABC Data1
configelement_XYZ Data1 Data2 Data3
configelement_XYZ Data1 Data2
假设一个文件名在输入文件中只出现一次,它不能包含换行符,并且 ;
除了分隔两个字段之外没有出现在该文件的任何其他地方,那么你可以在每个 Unix 机器上使用任何 shell 中的任何 awk 执行此操作:
awk '
BEGIN { FS=OFS=";" }
NR==FNR {
ARGV[ARGC++] =
re[] =
next
}
[=10=] ~ re[FILENAME] { print FILENAME, [=10=] }
' file
上面还假设你想对每个文件进行部分正则表达式匹配,因为这是你问题中的代码所做的,但这可能不是你真正想要做的最好的方法 - 见 其他可能性。
鉴于您新添加的示例输入,看起来您应该在第一个字段上进行完整的字符串匹配,而不是在整行中进行部分正则表达式匹配 - 如果那是正确的,则更改这些行:
re[] =
[=11=] ~ re[FILENAME] { print FILENAME, [=11=] }
至:
str[] =
== str[FILENAME] { print FILENAME, [=12=] }
此方法与其他 2 个当前答案之间的区别是:
- 调用 grep 的 shell 循环将比这慢几个数量级(请参阅 why-is-using-a-shell-loop-to-process-text-considered-bad-practice 中有关性能的部分以了解原因),并且
- 调用 getline 的 awk 脚本是手动编写代码来自动执行 awk 为你做的事情(即从文件中读取行并应用 conditions/actions)所以它需要更多的代码,如果你想要的话甚至更多添加与正在测试的文件有关的任何额外内容,例如要使用上面的 awk 脚本打印包含
X
的每一行,您只需添加包含 /X/
的行,因为它使用 awks 正常处理模式处理文件,而对于 getline 循环版本,您需要手动编写 if (/X/) print
因为你绕过了 awks 的正常处理模式。如果您正在考虑使用 getline,请先阅读 http://awk.freeshell.org/AllAboutGetline。
其他 2 种方法确实具有几乎不使用内存的优势,而上述脚本必须将所有原始输入文件内容存储在内存中,因此在极不可能的情况下 filename;regexp
对文件数十亿行长(即您的 PC 上有数十亿个文件要搜索)那么这可能是一个问题(但是 shell 循环需要几天或几周才能完成)。
Hello World(我的第一个问题:)
我有一个包含两个字段的文件。
我希望awk
使用一个字段作为搜索另一个字段的输入文件。
假设输入文件看起来像:
CONFIG_file123;configelement_ABC
CONFIG_file124;configelement_XYZ
现在我希望 awk
读取字段 1 (CONFIG_file123
) 并将其用作输入文件,在其中搜索字段 2 (configelement_ABC
) 输出然后继续到输入文件中的下一行。
像这样:
awk 'BEGIN{ RS = "\n"; ORS="\n" } {if ([=11=] ~ /configelement_ABC/) { print FILENAME ";" [=11=] }}' CONFIG_file123
非常感谢您!
如果这有帮助:
CONFIG_file123
configelement_ABA Data1 Data2 Data3
configelement_ABB Data1 Data2
configelement_ABC Data1
configelement_ABD Data1 Data2 Data3
configelement_XYW Data1 Data2
configelement_XYX Data1 Data2 Data3
configelement_XYY Data1
configelement_XYZ Data1 Data2 Data3
CONFIG_file124
configelement_ABA Data1 Data2 Data3
configelement_ABB Data1 Data2
configelement_ABC Data1 Data2
configelement_ABD Data1 Data2 Data3
configelement_XYW Data1 Data2
configelement_XYX Data1 Data2 Data3
configelement_XYY Data1 Data2
configelement_XYZ Data1 Data2
Output
CONFIG_file123;configelement_ABC Data1
CONFIG_file124;configelement_XYZ Data1 Data2
为此使用 awk
,虽然可能可行,但有点超出范围。您可以使用 bash
循环,而 grep
:
while IFS=';' read -r file string; do grep -F "$string" "$file"; done < list.txt
当然,它假定您的文件名或搜索字符串中没有 ;
。但是如果你有一些,你的问题将是未明确说明的:两个字段之间的真正分隔在哪里,而不是一个 ;
?
awk -F\; '{
config_file =
search_term =
while ((getline < config_file) > 0) {
if ([=10=] ~ search_term) {
print [=10=]
break
}
}
}' input_file
这将处理一个文件名 input_file
,它应该有两个字段,用分号分隔。它将每条记录中的第一个字段作为配置文件,第二个字段作为要搜索的词。
使用 getline
从 config_file 读取到 $0(它将被拆分为正常记录)。 while 循环将读取配置文件中的每一行并将每一行与搜索词进行比较。如果找到搜索词,它将打印出来并停止搜索。 (如果要打印匹配的每一行,请删除 break 语句。)
测试中使用的示例输入和配置文件:
$ cat input_file
CONFIG_file123;configelement_ABC Data1
CONFIG_file123;configelement_XYZ Data1 Data2 Data3
CONFIG_file124;configelement_XYZ Data1 Data2
$ cat CONFIG_file123
configelement_ABA Data1 Data2 Data3
configelement_ABB Data1 Data2
configelement_ABC Data1
configelement_ABD Data1 Data2 Data3
configelement_XYW Data1 Data2
configelement_XYX Data1 Data2 Data3
configelement_XYY Data1
configelement_XYZ Data1 Data2 Data3
$ cat CONFIG_file124
configelement_ABA Data1 Data2 Data3
configelement_ABB Data1 Data2
configelement_ABC Data1 Data2
configelement_ABD Data1 Data2 Data3
configelement_XYW Data1 Data2
configelement_XYX Data1 Data2 Data3
configelement_XYY Data1 Data2
configelement_XYZ Data1 Data2
输出:
configelement_ABC Data1
configelement_XYZ Data1 Data2 Data3
configelement_XYZ Data1 Data2
假设一个文件名在输入文件中只出现一次,它不能包含换行符,并且 ;
除了分隔两个字段之外没有出现在该文件的任何其他地方,那么你可以在每个 Unix 机器上使用任何 shell 中的任何 awk 执行此操作:
awk '
BEGIN { FS=OFS=";" }
NR==FNR {
ARGV[ARGC++] =
re[] =
next
}
[=10=] ~ re[FILENAME] { print FILENAME, [=10=] }
' file
上面还假设你想对每个文件进行部分正则表达式匹配,因为这是你问题中的代码所做的,但这可能不是你真正想要做的最好的方法 - 见
鉴于您新添加的示例输入,看起来您应该在第一个字段上进行完整的字符串匹配,而不是在整行中进行部分正则表达式匹配 - 如果那是正确的,则更改这些行:
re[] =
[=11=] ~ re[FILENAME] { print FILENAME, [=11=] }
至:
str[] =
== str[FILENAME] { print FILENAME, [=12=] }
此方法与其他 2 个当前答案之间的区别是:
- 调用 grep 的 shell 循环将比这慢几个数量级(请参阅 why-is-using-a-shell-loop-to-process-text-considered-bad-practice 中有关性能的部分以了解原因),并且
- 调用 getline 的 awk 脚本是手动编写代码来自动执行 awk 为你做的事情(即从文件中读取行并应用 conditions/actions)所以它需要更多的代码,如果你想要的话甚至更多添加与正在测试的文件有关的任何额外内容,例如要使用上面的 awk 脚本打印包含
X
的每一行,您只需添加包含/X/
的行,因为它使用 awks 正常处理模式处理文件,而对于 getline 循环版本,您需要手动编写if (/X/) print
因为你绕过了 awks 的正常处理模式。如果您正在考虑使用 getline,请先阅读 http://awk.freeshell.org/AllAboutGetline。
其他 2 种方法确实具有几乎不使用内存的优势,而上述脚本必须将所有原始输入文件内容存储在内存中,因此在极不可能的情况下 filename;regexp
对文件数十亿行长(即您的 PC 上有数十亿个文件要搜索)那么这可能是一个问题(但是 shell 循环需要几天或几周才能完成)。