Regex 使用sed提取子串

Regex 使用sed提取子串,regex,linux,sed,Regex,Linux,Sed,我有以下内容的日志文件: example.com - - - 127.0.01 [22/Sep/2013:07:22:22 +0000] "POST /api/test.php HTTP/1.1" 200 355 "-" "-" "{\x22id\x22:\x22 ... }}}" example.com - - - 127.0.01 [22/Sep/2013:07:22:22 +0000] "POST /api/test.php HTTP/1.1" 200 355 "-" "-" "{\

我有以下内容的日志文件:

example.com - - - 127.0.01 [22/Sep/2013:07:22:22 +0000]  "POST /api/test.php HTTP/1.1" 200 355 "-" "-" "{\x22id\x22:\x22 ... }}}"

example.com - - - 127.0.01 [22/Sep/2013:07:22:22 +0000]  "POST /api/test.php HTTP/1.1" 200 355 "-" "-" "{\x22id\x22:"{\x22 ... }}}"
我想将第一个
{\x22
提取到最后一个
}

因此,我使用以下sed命令:

cat test.txt  | sed -r  's/.+?"(\{.+\})".*/\1/g'
然而,它给了我

{\x22id\x22:\x22 ... }}}

{\x22 ... }}}
但是我想要

{\x22id\x22:\x22 ... }}}

{\x22id\x22:"{\x22 ... }}}

因为它的正则表达式引擎不支持非贪婪匹配,所以
+?
不适用于
sed

但是,如果考虑Perl,它是可能的:

perl -pe 's/.+?"(\{.+\})".*/\1/g' test.txt
{\x22id\x22:\x22 ... }}}
{\x22id\x22:"{\x22 ... }}}
或使用
egrep-o

egrep -o '\{.+\}' test.txt
{\x22id\x22:\x22 ... }}}
{\x22id\x22:"{\x22 ... }}}
使用
awk

awk '{sub(/[^{]*{/,"{");sub(/}"/,"}")}1' file
{\x22id\x22:\x22 ... }}}

{\x22id\x22:"{\x22 ... }}}
根据文本中要处理的内容,我使用变量剪切来更改任何其他“标记”。变量本身不需要,如果您确定剪切值不在文件中,您可以直接在sed中更改其内容,这可能对您有用(GNU sed):

贪婪在第一场比赛中是你的敌人,所以对
{\x22
使用分而治之的习惯用法。即放置一个唯一的标记(在本例中为
\n
),然后使用第二个替换命令删除字符串的第一部分。对于最后一个
}
贪婪是你的朋友,因为
*}
会自己找到最后一个匹配项


注意:如果第一个匹配是单个字符,比如说
X
,那么一个否定字符类
[^X]*
就足够了。但是,由于它是一个字符串(两个或多个字符),这将不起作用。

您也可以在激活perl引擎的情况下使用grep
grep-P
pgrep
。然后,命令将是
cat test.txt | grep-P-o”“
@ffledgeling:谢谢,更新后的答案是,yes
egrep
也将与
grep-P
的区别b/w
egrep
grep-E
相同,并且
grep-P
是他们使用的正则表达式引擎
egrep
ERE
pgrep
是Perl的引擎。虽然我从来没有看到过实际的差别。(注意pgrep和grep-P不一样,很抱歉混淆)
Cut="#CuT#"
sed -n --posix "s/\({\\\\x22.*}\)\"$/${Cut}\1/;s/.*${Cut}//p" sample.txt
sed 's/\({\\x22.*}\).*/\n\1/;s/.*\n//' file