我正在寻找两个匹配模式之间的界限。如果缺少任何开始或结束模式,则不应打印行。
正确输入:
a
***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****
b
Run Code Online (Sandbox Code Playgroud)
输出将是
***** BEGIN *****
BASH is awesome
BASH is awesome
***** END *****
Run Code Online (Sandbox Code Playgroud)
现在假设输入中缺少 END 模式
a
***** BEGIN *****
BASH is awesome
BASH is awesome
b
Run Code Online (Sandbox Code Playgroud)
不应打印行。
我试过 sed:
sed -n '/BEGIN/,/END/p' input
Run Code Online (Sandbox Code Playgroud)
如果缺少 END 模式,它将打印到最后一行的所有数据。
如何解决?
Rak*_*rma 10
您可以按如下方式完成此操作:
$ sed -e '
/BEGIN/,/END/!d
H;/BEGIN/h;/END/!d;g
' inp
Run Code Online (Sandbox Code Playgroud)
它的工作原理是,对于行的开始/结束范围,它将它们存储在保持空间中。然后删除直到遇到 END 行。在这一点上,我们回想起什么是保持。OTW,我们什么也得不到。哈。
cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' |
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac
Run Code Online (Sandbox Code Playgroud)
它通过tac
反转行来工作,以便sed
可以在两个顺序中找到两个分隔符。
与pcregrep
:
pcregrep -M '(?s)BEGIN.*?END'
Run Code Online (Sandbox Code Playgroud)
如果 BEGIN 和 END 在同一行,这也有效,但不适用于以下情况:
BEGIN 1 END foo BEGIN 2
END
Run Code Online (Sandbox Code Playgroud)
哪里pcregrep
捕获第一个BEGIN 1 END
,但不是第二个。
要处理这些,使用awk
,您可以执行以下操作:
awk '
!inside {
if (match($0, /^.*BEGIN/)) {
inside = 1
remembered = substr($0, 1, RLENGTH)
$0 = substr($0, RLENGTH + 1)
} else next
}
{
if (match($0, /^.*END/)) {
print remembered $0
if (substr($0, RLENGTH+1) ~ /BEGIN/)
remembered = ""
else
inside = 0
} else
remembered = remembered $0 ORS
}'
Run Code Online (Sandbox Code Playgroud)
在像这样的输入上:
a
BEGIN blah END BEGIN 1
2
END
b
BEGIN foo END
c
BEGIN
bar
END BEGIN
baz END
d
BEGIN
xxx
Run Code Online (Sandbox Code Playgroud)
它给:
BEGIN blah END BEGIN 1
2
END
BEGIN foo END
BEGIN
bar
END BEGIN
baz END
Run Code Online (Sandbox Code Playgroud)
两者都需要在内存中存储从 BEGIN 到后面的 END 的所有内容。因此,如果您有一个大文件,其第一行包含 BEGIN 但没有 END,则整个文件将无偿存储在内存中。
解决这个问题的唯一方法是对文件进行两次处理,但当然这只能在输入是常规文件(例如不是管道)时才能完成。
归档时间: |
|
查看次数: |
4307 次 |
最近记录: |