搜索具有多个字符串(全部包含,不是一个或另一个)的文件并打印行号

搜索具有多个字符串(全部包含,不是一个或另一个)的文件并打印行号

我想在某个目录的文件中搜索 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

相关内容