我已经很长时间没有使用sed
regexp 了,所以我有点生疏了。简化一下,我有以下输入作为我想从中提取网址的输入:
href="https://unix.stackexchange.com/"
我使用了 regex101.com 上非常有用的工具来优化我的表达式,以最初删除^
和第一个之间的所有内容"
:
s/^.*="//
然而,这不是我想要的,因为我不想依赖这个=
标志。但是,如果我将表达式修改为:
s/^.*"//
它匹配最后一个^
和最后一个之间的所有内容"
并忽略第一个。
显然,我在这里遗漏了一些令我感到沮丧的东西,但我们将不胜感激地收到任何帮助。
在 arch64 上运行 Ubuntu 21.04。
答案1
你缺少的是.*
匹配的贪婪地,消耗尽可能多的字符(包括"
直到最后一个字符)。
您可以"
使用 排除“之间的任何内容” [^"]*
,或者切换到提供非贪婪修饰符的正则表达式引擎,例如 Perl.*?
$ printf '%s\n' 'href="https://unix.stackexchange.com/"' | sed 's/^[^"]*"//'
https://unix.stackexchange.com/"
$ printf '%s\n' 'href="https://unix.stackexchange.com/"' | perl -pe 's/^.*?"//'
https://unix.stackexchange.com/"
OTOH,如果您真正想要的是裸露的 URL,您可以匹配并捕获第一个引用和最后一个引用之间的所有内容,并使用反向引用仅重新替换:
$ printf '%s\n' 'href="https://unix.stackexchange.com/"' | sed 's/^[^"]*"\(.*\)"/\1/'
https://unix.stackexchange.com/
严格来说,初始^[^"]*
不再需要是非贪婪的,并且可以^.*
在这种情况下替换为,因为正则表达式作为一个整体不能消耗第一个"
,同时仍然匹配第二个(尽管使其贪婪可能会引入不必要的回溯)。
答案2
cut
这就是发明这种工作的目的:
$ cut -d'"' -f2 file
https://unix.stackexchange.com/
答案3
您可以将所有内容匹配到第一的 "
和:
sed 's/^[^"]*"//'
这将从行的开头匹配^
几个(零个或多个*
)字符不是双引号 ( [^"]
) 后跟双引号"
。
答案4
使用gawk
:
awk '{print gensub(/(^.*")(.*")/, "\\2", "g");}' input
在此命令中,gawk
内置gensub()
函数使用反向引用()将所有捕获组替换为第二个捕获组\\2
。
如果我们想删除尾部引号,则命令可以更改为:
awk '{print gensub(/(^.*")(.*)(")/, "\\2", "g");}' input