我承认我更经常地寻找包含一些字符串的文件。
目前我这样做:
grep -rl string1 | xargs grep -l string2 | xargs grep -l string3
有没有一个工具可以做到这一点?
这grep
是string1
或string2
或string3
。
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
结束后的内容)作为分隔符。
(使用find
或zsh
递归 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 $?