我试图使用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|'

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


当前回答

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

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

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

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

-e "s,$,/,"

其他回答

还没有看到这个答案,所以这里是如何用vi或vim做到这一点:

vi -c '%s/\(http:\/\/.\{-}\/\).*/\1/ge | wq' file &>/dev/null

这将全局运行vi:%s替换(后面的g),如果没有找到模式,则避免引发错误(e),然后将结果更改保存到磁盘并退出。&>/dev/null可以防止GUI在屏幕上短暂闪烁,这很烦人。

有时候我喜欢用vi来处理超级复杂的正则表达式,因为(1)perl已经奄奄一息了,(2)vim有一个非常先进的正则表达式引擎,(3)在我日常使用的编辑文档中,我已经非常熟悉vi正则表达式了。

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

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

使用sed,我通常通过搜索除分隔符以外的任何东西来实现非贪婪搜索,直到分隔符:

echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*\)/.*;\1;p'

输出:

http://www.suon.co.uk

这是:

don't output -n search, match pattern, replace and print s/<pattern>/<replace>/p use ; search command separator instead of / to make it easier to type so s;<pattern>;<replace>;p remember match between brackets \( ... \), later accessible with \1,\2... match http:// followed by anything in brackets [], [ab/] would mean either a or b or / first ^ in [] means not, so followed by anything but the thing in the [] so [^/] means anything except / character * is to repeat previous group so [^/]* means characters except /. so far sed -n 's;\(http://[^/]*\) means search and remember http://followed by any characters except / and remember what you've found we want to search untill the end of domain so stop on the next / so add another / at the end: sed -n 's;\(http://[^/]*\)/' but we want to match the rest of the line after the domain so add .* now the match remembered in group 1 (\1) is the domain so replace matched line with stuff saved in group \1 and print: sed -n 's;\(http://[^/]*\)/.*;\1;p'

如果你想在域名后面加上反斜杠,那么在组中再加一个反斜杠来记住:

echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*/\).*;\1;p'

输出:

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

非贪婪的解决方案超过一个字符

这个帖子真的很老了,但我认为人们仍然需要它。 让我们假设你想杀死所有直到HELLO第一次出现的东西。你不能说[^HELLO]…

因此,一个很好的解决方案包括两个步骤,假设您可以在输入中留出一个您不期望的惟一单词,例如top_secit。

在这种情况下,我们可以:

s/HELLO/top_sekrit/     #will only replace the very first occurrence
s/.*top_sekrit//        #kill everything till end of the first HELLO

当然,对于一个简单的输入,你可以使用一个更小的单词,甚至可能是一个字符。

HTH!