我试图使用sed来清理url行来提取域。

所以从:

http://www.suepearson.co.uk/product/174/71/3816/

我想要:

http://www.suepearson.co.uk/

(不管后面有没有斜杠,都没有关系)

我试过:

 sed 's|\(http:\/\/.*?\/\).*|\1|'

And(转义非贪婪量词)

sed 's|\(http:\/\/.*\?\/\).*|\1|'

但我似乎不能让非贪婪量词(?)工作,所以它总是匹配整个字符串。


当前回答

@Daniel H(关于你对andcoz的回答的评论,虽然是很久以前的事了):删除后面的零

s,([[:digit:]]\.[[:digit:]]*[1-9])[0]*$,\1,g

这是关于清楚地定义匹配条件……

其他回答

使用纯(GNU) sed仍然有希望解决这个问题。尽管这不是一个通用的解决方案,在某些情况下,你可以使用“循环”来消除字符串中所有不必要的部分,就像这样:

sed -r -e ":loop" -e 's|(http://.+)/.*|\1|' -e "t loop"

-r:使用扩展的正则表达式(用于+和未转义的括号) 定义一个名为"loop"的新标签 -e:在sed中添加命令 "t loop":如果有成功的替换,则跳回标记"loop"

这里唯一的问题是它也会切掉最后一个分隔符('/'),但如果你真的需要它,你仍然可以在“循环”结束后简单地把它放回去,只需要在前面的命令行末尾追加这个额外的命令:

-e "s,$,/,"

另一个sed版本:

sed 's|/[:alnum:].*||' file.txt

它匹配/后面跟着一个字母数字字符(所以不是另一个正斜杠)以及其余字符,直到行尾。之后,它将什么也没有替换掉。删除它。)

sed 's|(http:\/\/[^\/]+\/).*|\1|'

这是如何使用sed健壮地进行多字符字符串的非贪婪匹配。假设你想改变每一个foo…Bar to <foo…Bar >,例如这个输入:

$ cat file
ABC foo DEF bar GHI foo KLM bar NOP foo QRS bar TUV

应该变成这样的输出:

ABC <foo DEF bar> GHI <foo KLM bar> NOP <foo QRS bar> TUV

要做到这一点,你将foo和bar转换为单独的字符,然后在它们之间使用这些字符的反字符:

$ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/<&>/g; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file
ABC <foo DEF bar> GHI <foo KLM bar> NOP <foo QRS bar> TUV

在上述:

/ / @ @A / g;s / {/ @B / g;s/}/@C/g正在将{和}转换为输入中不存在的占位符字符串,这样这些字符就可以转换为foo和bar。 s / foo / {/ g;S /bar/}/g将foo和bar分别转换为{和} S /{[^{}]*}/<&>/g正在执行我们想要的操作-将foo…Bar到<foo…Bar > s /} /酒吧/ g;S /{/foo/g将{和}转换回foo和bar。 s / @C /} / g;s / @B / {/ g;s/@ a /@/g将占位符字符串转换回原始字符。

请注意,上面的方法并不依赖于输入中不存在的任何特定字符串,因为它在第一步中就制造了这样的字符串,它也不关心你想要匹配的任何特定regexp的哪个出现,因为你可以在表达式中使用{[^{}]*}尽可能多的次数来隔离你想要的实际匹配和/或使用seds数值匹配操作符,例如只替换第二个出现:

$ sed 's/@/@A/g; s/{/@B/g; s/}/@C/g; s/foo/{/g; s/bar/}/g; s/{[^{}]*}/<&>/2; s/}/bar/g; s/{/foo/g; s/@C/}/g; s/@B/{/g; s/@A/@/g' file
ABC foo DEF bar GHI <foo KLM bar> NOP foo QRS bar TUV

基本的和扩展的Posix/GNU regex都不能识别非贪婪的量词;你需要稍后的正则表达式。幸运的是,这个上下文的Perl regex非常容易获得:

perl -pe 's|(http://.*?/).*|\1|'