我试图使用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 's|\(http://[^/]*/\).*|\1|g'

其他回答

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

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

还没有看到这个答案,所以这里是如何用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正则表达式了。

克利斯朵夫·西格哈特(Christoph Sieghart)著

在sed中获得非贪婪匹配的技巧是匹配除终止匹配的字符外的所有字符。我知道,这很简单,但我在这上面浪费了宝贵的时间,毕竟shell脚本应该是快速而简单的。所以以防别人需要

贪婪匹配

% echo "<b>foo</b>bar" | sed 's/<.*>//g'
bar

非贪婪匹配

% echo "<b>foo</b>bar" | sed 's/<[^>]*>//g'
foobar

在sed中模拟惰性(非贪婪)量词

以及所有其他正则表达式口味!

Finding first occurrence of an expression: POSIX ERE (using -r option) Regex: (EXPRESSION).*|. Sed: sed -r ‍'s/(EXPRESSION).*|./\1/g' # Global `g` modifier should be on Example (finding first sequence of digits) Live demo: $ sed -r 's/([0-9]+).*|./\1/g' <<< 'foo 12 bar 34' 12 How does it work? This regex benefits from an alternation |. At each position engine tries to pick the longest match (this is a POSIX standard which is followed by couple of other engines as well) which means it goes with . until a match is found for ([0-9]+).*. But order is important too. Since global flag is set, engine tries to continue matching character by character up to the end of input string or our target. As soon as the first and only capturing group of left side of alternation is matched (EXPRESSION) rest of line is consumed immediately as well .*. We now hold our value in the first capturing group. POSIX BRE Regex: \(\(\(EXPRESSION\).*\)*.\)* Sed: sed 's/\(\(\(EXPRESSION\).*\)*.\)*/\3/' Example (finding first sequence of digits): $ sed 's/\(\(\([0-9]\{1,\}\).*\)*.\)*/\3/' <<< 'foo 12 bar 34' 12 This one is like ERE version but with no alternation involved. That's all. At each single position engine tries to match a digit. If it is found, other following digits are consumed and captured and the rest of line is matched immediately otherwise since * means more or zero it skips over second capturing group \(\([0-9]\{1,\}\).*\)* and arrives at a dot . to match a single character and this process continues. Finding first occurrence of a delimited expression: This approach will match the very first occurrence of a string that is delimited. We can call it a block of string. sed 's/\(END-DELIMITER-EXPRESSION\).*/\1/; \ s/\(\(START-DELIMITER-EXPRESSION.*\)*.\)*/\1/g' Input string: foobar start block #1 end barfoo start block #2 end -EDE: end -SDE: start $ sed 's/\(end\).*/\1/; s/\(\(start.*\)*.\)*/\1/g' Output: start block #1 end First regex \(end\).* matches and captures first end delimiter end and substitues all match with recent captured characters which is the end delimiter. At this stage our output is: foobar start block #1 end. Then the result is passed to second regex \(\(start.*\)*.\)* that is same as POSIX BRE version above. It matches a single character if start delimiter start is not matched otherwise it matches and captures the start delimiter and matches the rest of characters.


直接回答你的问题

使用方法#2(带分隔符的表达式),你应该选择两个合适的表达式:

艾德:[^]\ / SDE: http:

用法:

$ sed 's/\([^:/]\/\).*/\1/g; s/\(\(http:.*\)*.\)*/\1/' <<< 'http://www.suepearson.co.uk/product/174/71/3816/'

输出:

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

注意:对于相同的分隔符,这将不起作用。

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