2017-08-14 24 views
1

如果我想從字符串中刪除第一個句點及其後面的所有內容,在sed中我可以例如這樣做:替換第n個正則表達式的問題

echo 2.6.0.3-8 | sed 's/\..*//' 

輸出:

2 

但是,如果我想刪除第二個時期,一切背後,我想我應該可以做這樣的(GNU SED):

echo 2.6.0.3-8 | sed 's/\..*//2g' 

然而輸出爲:

2.6.0.3-8 

從手冊:

'NUMBER' 只有更換REGEXP的NUMBERth比賽。

我在這裏錯過了什麼?

+1

你錯過了它是貪婪的。 '。*'是在吞噬一切,沒有第二個匹配。你可以使用'[^。] *'效果好於'。*' – stevesliva

回答

2

你有,但通過.*和貪婪燙傷更精確。所有你必須爲你的具體情況做是[^.]*替換.*

 
$ echo 2.6.0.3-8 | sed 's/\.[^.]*//2g' 
2.6 
$ echo 2.6.0.3-8 | sed 's/\.[^.]*//3g' 
2.6.0 
$ echo 2.6.0.3-8 | sed 's/\.[^.]*//1g' 
2 

[^.]意味着不是一個點的所有字符。

+0

+1,我看到並用'g'取代了其餘的行。請注意,這使得它成爲GNU特定的sed。你知道sed的便攜式解決方案嗎? – Thor

+0

我相信格倫的便攜式。 '-E'更多的是POSIX,然後是GNU sed的man頁面提供的'-r',但'-E'可以用於GNU sed。 – stevesliva

+0

是的你是對的。但是他並沒有使用我想工作的/// n'表格。我發現了一個有點駭人聽聞的方式,看到我的回答 – Thor

2

這是因爲表達是貪婪的。第一場比賽消耗.6.0.3-8,第二場比賽沒有剩餘文字。

你必須與你的正則表達式

$ sed -E 's/([^.]+(\.[^.]+){3}).*/\1/' <<<"2.6.0.3-8" 
2.6.0.3-8 
$ sed -E 's/([^.]+(\.[^.]+){2}).*/\1/' <<<"2.6.0.3-8" 
2.6.0 
$ sed -E 's/([^.]+(\.[^.]+){1}).*/\1/' <<<"2.6.0.3-8" 
2.6 
$ sed -E 's/([^.]+(\.[^.]+){0}).*/\1/' <<<"2.6.0.3-8" 
2 
+0

忽略我以前的評論,這很好,很好的答案。但是,它並沒有像我在這個問題中所做的那樣使用/// n'形式。 – Thor

+0

請參閱@史蒂夫的答案如何使用GNU sed和我的一個稍微黑客但便攜的方式做 – Thor

1

正如@stevesliva和@glennjackman所指出的,這裏的問題是正則表達式匹配整行,所以沒有第二個匹配。

似乎沒有一種通用的方法來實現用正則表達式替換。因此,通用的替代方案,消除了第二期,一切的背後是用Pd,如:

echo 2.6.0.3-8 | sed 's/\./\n/2; P; d' 

或者便攜:在這兩種情況下

echo 2.6.0.3-8 | sed -e $'s/\\./\\\n/2' -e P -e d 

輸出:

2.6 
+0

啊,現在我明白了。我沒有把注意力集中在一個與'g'相關的數字上,這是未定義的行爲。那就是說,分號應該是可移植的?我在OSX上用BSD sed用戶看到的通常的可移植性問題是,在花括號內必須有最終分號。 – stevesliva

+0

@stevesliva:的確我也這麼認爲,但是使用分號分隔時Debian的busybox sed的上述失敗 – Thor

+0

我猜這是busybox在將其傳遞給busybox sed之前解開單引號字符串的更多問題。即:'$ echo's/\ ./ \ n/2'| sed -f-'cause'sed:file-line 1:unterminated s'command' while'$ echo's/\\ ./ \\\ n/2'| sed -f-'沒有語法錯誤。這基本上是一個外殼擴展問題。除非您允許兩次字符串擴展,否則Sed不會看到正確的命令字符串。 – stevesliva