我想找到有“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..
应该匹配。
当前回答
如果你需要两个单词彼此接近,例如不超过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命令。
其他回答
Grep是这种操作的笨拙工具。
在大多数现代Linux系统中都可以找到pcregrep,可以用作
pcregrep -M 'abc.*(\n|.)*efg' test.txt
where -M,——multiline允许模式匹配多行
还有一个更新的pcre2grep。两者都是由PCRE项目提供的。
pcre2grep可以通过Mac Ports作为pcre2端口的一部分用于Mac OS X:
% sudo port install pcre2
并通过Homebrew为:
% brew install pcre
或者pcre2
% brew install pcre2
pcre2grep在Linux (Ubuntu 18.04+)上也可用
$ sudo apt install pcre2-utils # PCRE2
$ sudo apt install pcregrep # Older PCRE
我不确定是否可以使用grep,但sed使它非常简单:
sed -e '/abc/,/efg/!d' [file-with-content]
我在几天前发布了一个grep替代方案,它直接支持这一点,通过多行匹配或使用条件——希望它对搜索这里的人有用。下面是示例命令的样子:
多行:
sift -lm 'abc.*efg' testfile
条件:
sift -l 'abc' testfile --followed-by 'efg'
你也可以指定'efg'必须在一定的行数内跟在'abc'后面:
sift -l 'abc' testfile --followed-within 5:'efg'
你可以在sift-tool.org上找到更多信息。
作为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并在找到匹配时立即返回,因为我们只对退出码感兴趣
这个也能用吗?!
perl -lpne 'print $ARGV if /abc.*?efg/s' file_list
$ARGV包含从file_list读取当前文件时的文件名 /s修饰符跨换行搜索。