grep'ping 文件中的多个字符串(不一定在同一行)

grep'ping 文件中的多个字符串(不一定在同一行)

我承认我更经常地寻找包含一些字符串的文件。

目前我这样做:

grep -rl string1 | xargs grep -l string2 | xargs grep -l string3

有没有一个工具可以做到这一点?

grepstring1string2string3

grep -rl -e string1 -e string2 -e string3

string1我想要包含andstring2和的文件,string3但不一定在同一行。

grep也许现代的( )之一ag/ack/rg/sift可以做到这一点?

答案1

你可以grep这样使用:

grep -rzlP '(?s)(?=.*?string1)(?=.*?string2)(?=.*?string3)' .
  • (?s)已知的“dot-all”告诉grep允许点也.匹配ewline 字符。\n

  • (?=.*?pattern):正向先行,匹配.出现零次或多次*且非贪婪的任何字符,后跟模式(string1, string2, ...)。

您可以创建如下函数(POSIX bash& zsh):

mgrep() { eval grep -rzlP $(printf ''\''(?s)';
          printf '(?=.*?'\''"$%d"'\'')' $(eval echo {1..$#}); printf ''\''') . ; }

然后按如下方式调用,它将在当前工作目录中递归查找具有所有内容的文件图案在。

mgrep string1 string2 string3

它还将处理grep其本身支持的任何类型的模式(grep根据您的需求提前调整功能中的选项)。

mgrep string 'pattern with space' '\d+' [0-9]  [...]

答案2

agrep(原近似的grep,不是来自 ) 的那个tre,你可以做

agrep -ld '$x' 'pattern1;pattern2;pattern3'

我们使用无法匹配的正则表达式($x结束后的内容)作为分隔符。

(使用findzsh递归 glob 递归搜索目录中的所有文件)。

但请注意,模式与文件的全部内容匹配,而不是每个文件的每一行。

您可以使用 gawk 编写脚本:

PATTERNS='pattern1;pattern2;pattern3' gawk -e '
  BEGIN{n = split(ENVIRON["PATTERNS"], a, ";")}
  BEGINFILE{for (i in a) p[a[i]]; found = 0}
  {
    for (i in p)
      if ($0 ~ i) {
        if (++found == n) {print FILENAME; nextfile}
        delete p[i]
      }
  }' -E /dev/null file1 file2...

(虽然它很慢)。

答案3

根据 αГsнιn 的回答:

mgrep() {
    grep -rzlP "(?s)$(printf "(?=.*?%s)" "$@")" .
}

mgrep string1 string2 string3

答案4

以下提议很简单,但可能更有效、更稳健。

#!/bin/bash

tab=(one three five)

# grep_all's return status indicates if all patterns have at least
# one matching result in the text file specified as argument.

grep_all()
{
    local -n patterns=$1      # allows to refer to an array
    local file=$2

    # abort if a pattern is not found
    for pattern in "${patterns[@]}"; do
        if ! grep -q -e "$pattern" "$file"; then
            return 1
        fi
    done
}

grep_all tab file.txt
echo $?

相关内容