2012-02-22 226 views
0

我有一個殼變量:正則表達式的sed

all_apk_file="a 1 2.apk x.apk y m.apk" 

我想要的a 1 2.apkTEST來代替,使用命令:

echo $all_apk_file | sed 's/(.*apk){1}/TEST/g' 

.*apk裝置結束與apk{1}意味着只匹配一次,但不起作用;我只有原始變量作爲輸出:a 1 2.apk x.apk y m.apk

有誰能告訴我爲什麼?

+0

簡短回答是sed正在貪婪。既然你把'。*'作爲'。*'的一部分抓住前兩個'apk'組合,所以只能識別最後一個'apk'作爲最終組合。 – 2012-02-22 07:51:00

回答

0

一部分是在正規sed,在(){}在圖案普通字符,直到與反斜槓轉義。由於變量值中沒有括號,因此正則表達式永遠不會匹配。使用GNU sed,您還可以使用-r標誌啓用擴展正則表達式。如果你解決這個問題,你會再碰上這.*是貪婪的問題,而g修改實際上不會改變任何東西:因爲沒有在m.apk後的空間

$ echo $all_apk_file | sed 's/\(.*apk \)\{1\}/TEST/g' 
TESTy m.apk 
$ echo $all_apk_file | sed -r 's/(.*apk){1}/TEST/g' 
TESTy m.apk 
$ echo $all_apk_file | sed -r 's/(.*apk){1}/TEST/' 
TESTy m.apk 
$ 

它只是停在那裏變量的回顯值。

現在的問題是:你想要取代什麼?這聽起來像'一切,直到包括第一次出現apk在一個詞的結尾。這可能最容易通過Perl正則表達式中的尾隨上下文匹配或非貪婪匹配來完成。如果切換到Perl是一個選項,那麼這樣做。如果不是這樣,那麼在正則表達式中正常的sed並不是微不足道的。

$ echo $all_apk_file | sed 's/^[^.]* [^.][^.]*\.apk /TEST /' 
TEST x.apk y m.apk 
$ 

這看起來對任何事情沒有這點,其次是一片空白,其次是沒有點了一遍,.apk;這意味着允許的第一個點是2.apk中的那個。它適用於樣本數據;如果變量包含:

all_apk_file="a 1.2 2.apk m.apk y.apk 37" 

您需要調整它以符合您的要求。

+0

thx,詳細和清晰。 – Searene 2012-02-22 15:00:06

2

首先,讓你熟悉sed正則表達式,你需要使用-r開關(SED -r ...):

echo $all_apk_file | sed -r 's/(.*apk){1}/TEST/g' 
# returns TESTy m.apk 

看什麼返回:TESTy m.apk。這是因爲.*貪婪,所以它儘可能匹配。也就是說,.*a 1 2.apk x匹配,並且您曾說過要替換.*apk,即a 1 2.apk x.apk與'TEST',導致TESTy m.apk(注意正則表達式中'.apk'後面的空格,這就是爲什麼匹配並沒有擴展到最後一個'.apk',後面沒有空格)。

通常,一個可以改變.*.*?使其非貪婪,但在sed不支持這種行爲。

所以,要解決它,你只需要讓你的正則表達式更具限制性。

很難說出你想做什麼 - 刪除「.apk」中第三個結尾的前三個單詞並替換爲「TEST」?在這種情況下,可以使用正則表達式:

[a-z0-9]+ +[a-z0-9]+ +[a-z0-9]+\.apk 

結合的「i」切換(不區分大小寫)。

您必須給出決定刪除內容的邏輯(前三個單詞,第一個'.apk'單詞等任意數量的單詞),以便我們用正則表達式進一步幫助您。

其次,你已經把'g'開關放到你的正則表達式中。這意味着全部匹配模式將被替換,而您似乎只希望第一個被替換。所以刪除'g'開關。

最後,所有thse的組合:問題的

echo $all_apk_file | sed -r 's/[a-z0-9]+ +[a-z0-9]+ +[a-z0-9]+\.apk/TEST/i' 
# TEST x.apk y m.apk 
+1

這可以在perl中用'echo $ all_apk_file | perl -pe's/^(。*?\。apk)/ TEST /''如果切換到perl是一個選項。 – AndrewF 2012-02-22 04:01:03

1

這可能會爲你工作:

echo "$all_apk_file" | sed 's/apk/\n/;s/.*\n/TEST/' 
TEST x.apk y m.apk 

至於爲什麼你的正則表達式沒有工作,看到@ mathematical.coffee和@Jonathan萊弗勒的優秀解釋。

s/apk/\n/s/apk/\n/1同義,意思是用\n代替第一次出現apk。由於sed使用\n作爲記錄分隔符,我們知道它不會發生在傳遞給sed命令的任何初始字符串中。有了我們腰帶上的這兩個事實,我們可以拆分字符串。

N.B.如果你想取代第二個apk然後s/apk/\n/2將符合該法案。當然,對於apk的最後發生,則.*apk發揮作用。