我尝试解析卷曲响应,以便检索使用alt标记captcha
标识的img src。
为了测试我的sed
表达式,我尝试了以下内容:
echo 'alt="captcha" src="http://example.com/foo.html" /></p>' | sed -n 's/.*alt="captcha" src="\([^"]*\)/\1/p'
然而这回声
http://example.com/foo.html" /></p>
我怎样才能简单地返回
http://example.com/foo.html
我是sed
的新手,所以我想知道我哪里出错了。
答案 0 :(得分:3)
这个答案解释了sed
的行为,但是123 - 他们在评论中简明扼要地给出了sed
问题的正确答案 - 指出了一个更好的选择,如果你有 GNU grep
:grep -oP 'alt="captcha" src="\K[^"]*'
。 GNU grep
的{{1}}选项支持PCREs,它们比-P
中提供的正则表达式更强大。
该问题与贪婪无关,而是与您的正则表达式仅与该行的部分匹配的事实:
要在sed
中提取子字符串,您的正则表达式必须与整行 匹配。否则,正则表达式匹配 的任何部分只是通过 ,就像您案例中的尾随sed
一样;这是一个修复:
" /></p>
请注意我添加的尾随$ echo 'alt="captcha" src="http://example.com/foo.html" /></p>' |
sed -n 's/.*alt="captcha" src="\([^"]*\).*/\1/p'
http://example.com/foo.html
,这可确保该行的其余部分也匹配。
没有它,匹配后输入行的剩余部分将简单地附加到替换的结果中;即.*
部分。 更正确:该行的剩余部分根本不会被替换。
因此,通常,您使用的方法如下(伪表示法):
" /></p>
同样,正则表达式必须与整行匹配才能生效。
由于sed 's/^...<capture-group>...$/\1/p'
的贪婪匹配,您既不需要sed
也不需要^
,但您可以选择添加它以明确意图。
警告:如果您的捕获组没有歧义, $
可以匹配该行的余数,但是{{1} } 之前匹配所有
一个简单示例来演示问题:
.*
请注意.*
如何包含$ sed -n 's/[^"]*"\([^"]*\)/>>\1<</p' <<<'before"foo"after' # WRONG
>>foo<<"after
按预期捕获的感兴趣的子字符串 - \1
之间的字符串\([^"]*\)
- 但是,因为正则表达式在之前停止匹配结束foo
,该行的剩余部分 - "..."
- 仍然输出。
固定版本,附加"
以确保整行匹配:
"after
另请注意.*
如何用于匹配行的开头到捕获组;由于$ sed -n 's/[^"]*"\([^"]*\).*/>>\1<</p' <<<'before"foo"after'
>>foo<<
的贪婪匹配,[^"]*"
不在这里工作:
.*
sed
贪婪地匹配 last $ sed -n 's/.*"\([^"]*\).*/>>\1<</p' <<<'before"foo"after' # WRONG
>>after<<
的所有内容,因此捕获组会捕获.*"
,这是非{"
的运行1}}字符。 关闭后 after
。
答案 1 :(得分:0)
使用sed分组。它总是我的转到!
Sed正则表达式:
echo 'alt="captcha" src="http://example.com/foo.html" /></p>' | sed 's/\(^alt.*src=\"\)\(.*\)\(\".*p>\)/\2/g'
<强>输出强>
http://example.com/foo.html