awk 是发明 grep、shell 等的人发明的工具,用于执行此类一般文本操作工作,因此不确定为什么您要尝试避免使用它。
如果您正在寻找简洁性,这里有 GNU awk 一行代码来完成您所要求的操作:
awk 'NR==FNR{a[$0];next} {for(s in a) if(!index($0,s)) exit 1}' strings RS='^$' file
这里还有很多其他信息和选项:
假设你真的在寻找字符串,那就是:
awk -v strings='string1 string2 string3' '
BEGIN {
numStrings = split(strings,tmp)
for (i in tmp) strs[tmp[i]]
}
numStrings == 0 { exit }
{
for (str in strs) {
if ( index($0,str) ) {
delete strs[str]
numStrings--
}
}
}
END { exit (numStrings ? 1 : 0) }
' file
一旦所有字符串匹配,上面的代码将停止读取文件。
如果您正在寻找正则表达式而不是字符串,那么使用 GNU awk 进行多字符 RS 并在 END 部分保留 $0 ,您可以这样做:
awk -v RS='^$' 'END{exit !(/regexp1/ && /regexp2/ && /regexp3/)}' file
实际上,即使它是字符串,你也可以这样做:
awk -v RS='^$' 'END{exit !(index($0,"string1") && index($0,"string2") && index($0,"string3"))}' file
上述 2 个 GNU awk 解决方案的主要问题是,像 @anubhava 的 GNU grep -P 解决方案一样,整个文件必须一次读入内存,而使用上面的第一个 awk 脚本,它可以在任何 awk 中工作任何 UNIX 机器上的任何 shell,一次仅存储一行输入。
我看到您在问题下添加了一条评论,表示您可能有数千个“模式”。假设您的意思是“字符串”,那么您可以从文件中读取它们,而不是将它们作为参数传递给脚本,例如使用用于多字符 RS 的 GNU awk 和每行一个搜索字符串的文件:
awk '
NR==FNR { strings[$0]; next }
{
for (string in strings)
if ( !index($0,string) )
exit 1
}
' file_of_strings RS='^$' file_to_be_searched
对于正则表达式它是:
awk '
NR==FNR { regexps[$0]; next }
{
for (regexp in regexps)
if ( $0 !~ regexp )
exit 1
}
' file_of_regexps RS='^$' file_to_be_searched
如果您没有 GNU awk 并且您的输入文件不包含 NUL 字符,那么您可以通过使用获得与上面相同的效果RS='\0'
代替RS='^$'
或者在读取变量时一次追加一行,然后在 END 部分处理该变量。
如果您的 file_to_be_searched 太大而无法放入内存,那么对于字符串来说就是这样:
awk '
NR==FNR { strings[$0]; numStrings=NR; next }
numStrings == 0 { exit }
{
for (string in strings) {
if ( index($0,string) ) {
delete strings[string]
numStrings--
}
}
}
END { exit (numStrings ? 1 : 0) }
' file_of_strings file_to_be_searched
以及正则表达式的等效项:
awk '
NR==FNR { regexps[$0]; numRegexps=NR; next }
numRegexps == 0 { exit }
{
for (regexp in regexps) {
if ( $0 ~ regexp ) {
delete regexps[regexp]
numRegexps--
}
}
}
END { exit (numRegexps ? 1 : 0) }
' file_of_regexps file_to_be_searched