我想找到有“abc”和“efg”的文件,这两个字符串在该文件中的不同行。一个包含以下内容的文件:
blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..
应该匹配。
我想找到有“abc”和“efg”的文件,这两个字符串在该文件中的不同行。一个包含以下内容的文件:
blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..
应该匹配。
当前回答
随着几个月前ugrep的发布:
ugrep 'abc(\n|.)+?efg'
这个工具是高度优化的速度。它也是GNU/BSD/PCRE-grep兼容的。
注意我们应该使用惰性重复+?,除非您想将所有efg行匹配在一起,直到文件中的最后一个efg。
其他回答
我不确定是否可以使用grep,但sed使它非常简单:
sed -e '/abc/,/efg/!d' [file-with-content]
#!/bin/bash
shopt -s nullglob
for file in *
do
r=$(awk '/abc/{f=1}/efg/{g=1;exit}END{print g&&f ?1:0}' file)
if [ "$r" -eq 1 ];then
echo "Found pattern in $file"
else
echo "not found"
fi
done
这应该可以工作:
cat FILE | egrep 'abc|efg'
如果有多个匹配项,可以使用grep -v过滤掉
作为Balu Mohan的答案的替代方案,可以只使用grep、head和tail来强制模式的顺序:
for f in FILEGLOB; do tail $f -n +$(grep -n "pattern1" $f | head -n1 | cut -d : -f 1) 2>/dev/null | grep "pattern2" &>/dev/null && echo $f; done
不过,这个不太漂亮。格式化得更容易读:
for f in FILEGLOB; do
tail $f -n +$(grep -n "pattern1" $f | head -n1 | cut -d : -f 1) 2>/dev/null \
| grep -q "pattern2" \
&& echo $f
done
这将打印所有“pattern2”出现在“pattern1”之后,或者两者都出现在同一行的文件名称:
$ echo "abc
def" > a.txt
$ echo "def
abc" > b.txt
$ echo "abcdef" > c.txt; echo "defabc" > d.txt
$ for f in *.txt; do tail $f -n +$(grep -n "abc" $f | head -n1 | cut -d : -f 1) 2>/dev/null | grep -q "def" && echo $f; done
a.txt
c.txt
d.txt
解释
Tail -n +i -打印第i行之后的所有行,包括 Grep -n -在匹配的行前加上行号 头-n1 -只打印第一行 Cut -d: -f 1 -打印第一个切割列,使用:作为分隔符 2>/dev/null -如果$()表达式返回空,则出现沉默尾部错误输出 Grep -q—关闭Grep并在找到匹配时立即返回,因为我们只对退出码感兴趣
如果你需要两个单词彼此接近,例如不超过3行,你可以这样做:
find . -exec grep -Hn -C 3 "abc" {} \; | grep -C 3 "efg"
同样的例子,但是只过滤*.txt文件:
find . -name *.txt -exec grep -Hn -C 3 "abc" {} \; | grep -C 3 "efg"
如果你想,你也可以用正则表达式替换grep命令。