我想找到有“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..
应该匹配。
当前回答
sed应该足够了,就像海报LJ上面说的,
而不是!d,你可以简单地使用p打印:
sed -n '/abc/,/efg/p' file
其他回答
虽然sed选项是最简单、最简单的,但遗憾的是,LJ的一行程序并不是最可移植的。那些受困于C Shell(而不是bash)版本的人将需要摆脱他们的刘海:
sed -e '/abc/,/efg/\!d' [file]
不幸的是,这一行在bash等中不起作用。
我不知道如何用grep做到这一点,但我会用awk做这样的事情:
awk '/abc/{ln1=NR} /efg/{ln2=NR} END{if(ln1 && ln2 && ln1 < ln2){print "found"}else{print "not found"}}' foo
不过,你需要注意如何做到这一点。您希望正则表达式匹配子字符串还是整个单词?适当添加\w标记。此外,虽然这严格符合您陈述的示例,但当abc在efg之后第二次出现时,它并不完全有效。如果你想处理这个问题,在/abc/ case等中添加一个If。
在所有文件中递归搜索(在每个文件中的多行中),同时存在两个字符串(即string1和string2在不同的行中,并且都存在于同一个文件中):
grep -r -l 'string1' * > tmp; while read p; do grep -l 'string2' $p; done < tmp; rm tmp
在所有文件中递归搜索(在每个文件中的多行中),使用EITHER字符串存在(即string1和string2在不同的行中,并且在同一个文件中存在):
grep -r -l 'string1\|string2' *
你至少有几个选择
DOTALL方法
用(?s) DOTALL the。包含\n的字符 你也可以使用一个超前(?=\n)——不会在匹配中被捕获
example-text:
true
match me
false
match me one
false
match me two
true
match me three
third line!!
{BLANK_LINE}
命令:
grep -Pozi '(?s)true.+?\n(?=\n)' example-text
-p用于perl正则表达式
-o只匹配模式,而不是整行
-z允许换行
-i不区分大小写
输出:
true
match me
true
match me three
third line!!
注:
- +? makes modifier non-greedy so matches shortest string instead of largest (prevents from returning one match containing entire text)
你可以使用老式的O.G.手动方法,使用\n
命令:
grep -Pozi 'true(.|\n)+?\n(?=\n)'
输出:
true
match me
true
match me three
third line!!
作为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并在找到匹配时立即返回,因为我们只对退出码感兴趣