我想在某个目录的文件中搜索 2 个(或更多)字符串并打印行号。
搜索结果应仅包含那些文件全部所提到的字符串存在(可能在同一行,也可能不在同一行)。它应该排除包含任一字符串但不是全部字符串的文件。
实现此目的的便捷命令应该是什么?
答案1
使用 GNU awk 您可以执行以下操作:
awk 'BEGINFILE { n1=n2=0 }
/str1/ { n1=FNR }
/str2/ { n2=FNR }
ENDFILE { if (n1&&n2) print FILENAME,n1,n2 }
' files...
要考虑的字符串列表的变体:
awk -v s="str1 str2 str3" '
BEGIN { n=split(s,str) ; m=(2^n)-1 }
BEGINFILE { f=0 }
{ for (i=1; i<=n; i++)
if ($0 ~ str[i]) {
l[i] = FNR
f += 2^(i-1)
}
}
ENDFILE {
if (f==m)
for (i=1; i<=n; i++) print FILENAME,l[i]
}
' files...
这些命令最好放入脚本文件中执行,并替换列表files...
以"$@"
将文件作为参数传递给脚本。
一个脚本,比如“findall”,用于传递目录(如评论中所要求的)和搜索字符串可以是:
dir=${1:?}
shift
cd "$dir" || exit 1
awk -v s="$*" '
...as above...
' *
并可称为findall dir str1 str2 ... strN
. (请注意,搜索字符串不得包含空格字符。)
答案2
一种方法是首先列出匹配的文件,然后再次读取文件以找到所需的行。只要匹配文件不太大或太多,这种方法就很有效。
假设最近有足够的 GNU 实用程序 (Linux/Cygwin) 来避免包含特殊字符的文件名问题:
grep -Rlz -Fe "foo" . |
xargs -0 grep -lz -Fe "bar" /dev/null |
xargs -0 grep -lz -Fe "qux" /dev/null |
xargs -0 awk '/foo|bar|qux/ {print FNR}' /dev/null