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

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


当前回答

sed -E将正则表达式解释为扩展(现代)正则表达式

更新:MacOS X为-E, GNU sed为-r。

其他回答

在这种特定情况下,您可以在不使用非贪婪正则表达式的情况下完成工作。

试试这个非贪婪的正则表达式[^/]*来代替。*?:

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

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

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

因为您特别指出您正在尝试使用sed(而不是perl、cut等),所以请尝试分组。这就避免了非贪婪标识符可能无法被识别。第一组是协议(即协议)。'http://', 'https://', 'tcp://',等等)。第二组是域:

echo "http://www.suon.co.uk/product/1/7/3/" | sed "s|^\(.*//\)\([^/]*\).*$|\1\2|"

如果您不熟悉分组,请从这里开始。

您还应该考虑没有匹配界限的情况。你是否想输出这一行。如果不匹配,我这里的示例不会输出任何内容。

你需要前缀到第三个/,所以选择两次字符串的任何长度不包含/和后面的/,然后字符串的任何长度不包含/,然后匹配/后面的任何字符串,然后打印选择。这个想法适用于任何单个的char delims。

echo http://www.suepearson.co.uk/product/174/71/3816/ | \
  sed -nr 's,(([^/]*/){2}[^/]*)/.*,\1,p'

使用sed命令,您可以快速删除前缀或delim选择,如:

echo 'aaa @cee: { "foo":" @cee: " }' | \
  sed -r 't x;s/ @cee: /\n/;D;:x'

这比一次吃焦肉快多了。

如果之前匹配成功,跳转到标签。在第一道线/之前加\n。移除到第一个\n。如果添加了\n,则跳转到结束并打印。

如果有开始和结束delim,很容易删除结束delim,直到你到达你想要的第n -2个元素,然后做D技巧,在结束delim后删除,如果不匹配跳转到删除,在开始delim和打印之前删除。这仅在开始/结束分隔成对出现时有效。

echo 'foobar start block #1 end barfoo start block #2 end bazfoo start block #3 end goo start block #4 end faa' | \
  sed -r 't x;s/end//;s/end/\n/;D;:x;s/(end).*/\1/;T y;s/.*(start)/\1/;p;:y;d'

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

这个帖子真的很老了,但我认为人们仍然需要它。 让我们假设你想杀死所有直到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!