显示模式匹配之前的 n 行和之后的 m 行,n & m 本身就是模式匹配
Display n lines before and m lines after a pattern match were n & m are themselves pattern matches
我有这样的数据:
foo
...
bar
...
pattern
...
]
我需要先匹配到 'pattern' 然后显示 'pattern' 之前的所有内容直到 'foo' 以及模式之后的所有内容到 ']'
grep 应该这样做:
grep pattern -A grep foo -B grep ]
可惜不是。
答案不需要包含 grep。
欢迎 awk、sed 和其他人。
Soo...如果包含与 pattern
匹配的内容,您想要在匹配 foo
的内容和匹配 ]
的内容之间打印一个部分,对吗?然后
sed -n '/foo/ { :a; N; /\]/!ba /pattern/ p }' filename
sed 代码的工作原理如下:
/foo/ { # if a line matches foo
:a # jump label
N # fetch the next line and append it to the pattern space
/\]/! ba # if the result does not match ] (that is, if the last fetched
# line does not contain something that matches ]), go back to :a
/pattern/ p # if in all these lines, there is something that matches the
# pattern, print them
}
在前面使匹配非贪婪 -- 也就是说,如果在文件中
1
foo
2
foo
3
pattern
4
]
5
匹配应包括 3
和 4
但不包括 2
,脚本可以这样修改(或类似的,取决于您要使用的模式):
sed -n '/foo/ { :a; N; /\n[^\n]*foo/ s/.*\n//; /\]/!ba /pattern/ p }' filename
其中 /\n[^\n]*foo/ s/.*\n//
将删除最后获取的行之前的所有内容,如果该行中的某些内容匹配 foo
。
如果您的图案是线条图案(即,如果它们包含 ^
或 $
),则需要对其进行修改。一旦模式 space 中有多于一行,^
将匹配模式 space 的开头和 $
结尾 ],不在一条线上。然后,您可以使用 \n
来匹配行尾。例如,如果你想在正好是 foo
和 ]
的行之间进行非贪婪匹配,如果它们之间有一条恰好是 pattern
的行,你可以使用
sed -n '/^foo$/ { :a; N; /\nfoo$/ s/.*\n//; /\n\]$/!ba /\npattern\n/ p }' filename
这是一个awk
awk '/foo/ {t=1} t {a[++b]=[=10=]} /pattern/ {f=1} /^]/ {if (f) for (i=1;i<=b;i++) print a[i];delete a;b=t=f=0}' file
示例数据
cat file
foo
data
more
]
foo
...
bar
...
pattern
...
]
more
foo
here
yes
]
end
测试awk
awk '/foo/ {t=1} t {a[++b]=[=12=]} /pattern/ {f=1} /^]/ {if (f) for (i=1;i<=b;i++) print a[i];delete a;b=t=f=0}'
foo
...
bar
...
pattern
...
]
一些更易读的:
awk '
/foo/ {t=1}
t {a[++b]=[=13=]}
/pattern/ {f=1}
/^]/ {if (f)
for (i=1;i<=b;i++)
print a[i]
delete a
b=t=f=0
}
'
测试是否找到foo
,设置t
为true
如果 t
为真,将所有行存储在数组 a
中
如果找到 pattern
,则设置标志 f
如果找到 ]
,则测试标志 f
是否为真,然后打印数组 a
重置所有提示并重新开始。
单行使用 perl:
perl -wln -0777 -e 'm/foo((?!foo).)*pattern[^\]]*\]/s and print $&;' [filename]
输入:
foo
foo
...
bar
...
pern
...
]
]
foo
...
pattern
]
]
foo
]
输出:
perl -wln -0777 -e 'm/foo((?!foo).)*pattern[^\]]*\]/s and print $&;' testtest
foo
...
pattern
]
一些要点:
- 在perl中用
m/.../s
开启单行模式参考this post:
- 正则表达式
foo((?!foo).)*pattern[^\]]*\]
foo
匹配第一个foo
((?!foo).)*
避免在匹配部分使用negative lookahead 匹配foo
pattern
匹配模式
[^\]]*\]
以下部分不应包含 ]
并以 ]
结尾
我有这样的数据:
foo
...
bar
...
pattern
...
]
我需要先匹配到 'pattern' 然后显示 'pattern' 之前的所有内容直到 'foo' 以及模式之后的所有内容到 ']'
grep 应该这样做:
grep pattern -A grep foo -B grep ]
可惜不是。
答案不需要包含 grep。 欢迎 awk、sed 和其他人。
Soo...如果包含与 pattern
匹配的内容,您想要在匹配 foo
的内容和匹配 ]
的内容之间打印一个部分,对吗?然后
sed -n '/foo/ { :a; N; /\]/!ba /pattern/ p }' filename
sed 代码的工作原理如下:
/foo/ { # if a line matches foo
:a # jump label
N # fetch the next line and append it to the pattern space
/\]/! ba # if the result does not match ] (that is, if the last fetched
# line does not contain something that matches ]), go back to :a
/pattern/ p # if in all these lines, there is something that matches the
# pattern, print them
}
在前面使匹配非贪婪 -- 也就是说,如果在文件中
1
foo
2
foo
3
pattern
4
]
5
匹配应包括 3
和 4
但不包括 2
,脚本可以这样修改(或类似的,取决于您要使用的模式):
sed -n '/foo/ { :a; N; /\n[^\n]*foo/ s/.*\n//; /\]/!ba /pattern/ p }' filename
其中 /\n[^\n]*foo/ s/.*\n//
将删除最后获取的行之前的所有内容,如果该行中的某些内容匹配 foo
。
如果您的图案是线条图案(即,如果它们包含 ^
或 $
),则需要对其进行修改。一旦模式 space 中有多于一行,^
将匹配模式 space 的开头和 $
结尾 ],不在一条线上。然后,您可以使用 \n
来匹配行尾。例如,如果你想在正好是 foo
和 ]
的行之间进行非贪婪匹配,如果它们之间有一条恰好是 pattern
的行,你可以使用
sed -n '/^foo$/ { :a; N; /\nfoo$/ s/.*\n//; /\n\]$/!ba /\npattern\n/ p }' filename
这是一个awk
awk '/foo/ {t=1} t {a[++b]=[=10=]} /pattern/ {f=1} /^]/ {if (f) for (i=1;i<=b;i++) print a[i];delete a;b=t=f=0}' file
示例数据
cat file
foo
data
more
]
foo
...
bar
...
pattern
...
]
more
foo
here
yes
]
end
测试awk
awk '/foo/ {t=1} t {a[++b]=[=12=]} /pattern/ {f=1} /^]/ {if (f) for (i=1;i<=b;i++) print a[i];delete a;b=t=f=0}'
foo
...
bar
...
pattern
...
]
一些更易读的:
awk '
/foo/ {t=1}
t {a[++b]=[=13=]}
/pattern/ {f=1}
/^]/ {if (f)
for (i=1;i<=b;i++)
print a[i]
delete a
b=t=f=0
}
'
测试是否找到foo
,设置t
为true
如果 t
为真,将所有行存储在数组 a
中
如果找到 pattern
,则设置标志 f
如果找到 ]
,则测试标志 f
是否为真,然后打印数组 a
重置所有提示并重新开始。
单行使用 perl:
perl -wln -0777 -e 'm/foo((?!foo).)*pattern[^\]]*\]/s and print $&;' [filename]
输入:
foo
foo
...
bar
...
pern
...
]
]
foo
...
pattern
]
]
foo
]
输出:
perl -wln -0777 -e 'm/foo((?!foo).)*pattern[^\]]*\]/s and print $&;' testtest
foo
...
pattern
]
一些要点:
- 在perl中用
m/.../s
开启单行模式参考this post: - 正则表达式
foo((?!foo).)*pattern[^\]]*\]
foo
匹配第一个foo((?!foo).)*
避免在匹配部分使用negative lookahead 匹配pattern
匹配模式[^\]]*\]
以下部分不应包含]
并以]
结尾
foo