输入示例:
START{
some text
{
more text}
almost there
}
nothing important{
...
期望的输出:
START{
some text
{
more text}
almost there
}
第一个左括号可以位于不同的位置:
START{...
START {...
START
{...
开始还可以包含特殊字符,例如:*
我想打印出所有内容,包括从 START 开始的内容以及第一次匹配之间的所有内容{}
(在 bash 中)。我正在考虑有一个计数器,当它找到时增加{
并在找到时减少}
。当结果为零时,它将停止打印(大括号始终匹配)。
答案1
一种简单的暴力方法,可以在所有 Unix 机器上的任何 shell 中的任何 awk 中工作:
$ cat tst.awk
s=index($0,"START") { $0=substr($0,s); f=1 }
f { rec = rec $0 RS }
END {
len = length(rec)
for (i=1; i<=len; i++) {
char = substr(rec,i,1)
if ( char == "{" ) {
++cnt
}
else if ( char == "}" ) {
if ( --cnt == 0 ) {
print substr(rec,1,i)
exit
}
}
}
}
$ awk -f tst.awk file
START{
some text
{
more text}
almost there
}
答案2
和pcregrep
:
start_word='START'
pcregrep -Mo "(?s)\Q$start_word\E\h*(\{(?:[^{}]++|(?1))*+\})" < your-file
使用zsh
内置函数:
set -o rematchpcre
start_word='START'
[[ $(<your-file) =~ "(?s)\Q$start_word\E\h*(\{(?:[^{}]++|(?1))*+\})" ]] &&
print -r -- $MATCH
它们使用 PCRE 的递归正则表达式功能,上面(?1)
回顾了第一(...)
对中的正则表达式。
如果你既没有pcregrep
也没有zsh
,您可以随时求助于真实的事情( PCRE 中perl
的P
):
perl -l -0777 -sne '
print $& if /\Q$start_word\E\h*(\{(?:[^{}]++|(?1))*+\})/s
' -- -start_word='START' < your-file
(请注意,除了其中perl
一个之外,所有其他都假设$start_word
不包含\E
)。