2016-05-30 50 views
0

我需要替換名字的「無關緊要」的部分。這需要在bash腳本中完成。爲此,我需要刪除中間單詞「VAN」,「DEN」,「DE」和「DER」。

要做到這一點,我使用內置的替換(問題降低到2行):

line="STIG VAN DE WYNKELE"; 
line=${line//@(' VAN '|' DEN '|' DE '|' DER ')/' '}; 
echo $line; 

輸出:

STIG DE WYNKELE 

預期輸出:

STIG WYNKELE 

看起來像@(...)與中間單詞中的一個匹配,消除了這個中間單詞的所有出現,但它不匹配其他單詞RS。

問題:我的語法錯了嗎?如果不是,我將如何刪除這些字詞? sed需要文件,而我的輸入是一個變量,並且修改過的文本也應該存儲在一個變量中。 ($行應改變)

+1

'sed'不需要的文件,這是一個流編輯器。 'foo = $(echo「$ foo」| sed ...)'是一個常見的習慣用語。 –

+0

常見,但如果'$ foo'很短,通常不需要。 – chepner

回答

3

bash不會回溯。首先,它發現VAN在輸入:

STIG VAN DE WYNKELE 
    ^^^^^| 

(其中|表示其指針在掃描)。

更換VAN後,你有

STIG DE WYNKELE 
    | 

你會發現DE沒有開始D字符串中發現的;您剛插入的空間不會被bash檢查。

相反,從每個圖案刪除前導空格和刪除的,而不是用空格代替它匹配:

echo "${line//@('VAN '|'DEN '|'DE '|'DER ')}" 

當然,這個問題是你現在可能會下降一匹配發生在單詞的末尾。有一場比賽不會避免這種情況發生;相反,在一個循環中做多個替換:

for word in VAN DEN DE DER; do 
    line=${line// $word/} 
done 
+0

這解決了這個問題,看起來像沒有任何副作用的最佳方式,謝謝! – Bertware

+0

只用一個匹配就可以,但只能用於查找(在bash中不支持)。 – choroba

0

你不需要任何extglob模式。你可以只用參數擴展:

${line/ */} 

例子:

$ line="STIG VAN DE WYNKELE" 
$ echo ${line/ */} 
STIG WYNKELE 
4

您需要設置extglob選項。另外,刪除引號,並將該空間移到替代方法之外。您可以進一步縮短表達式:

#!/bin/bash 
line="STIG VAN DE DEN DER WYNKELE" 
shopt -s extglob 
line=${line//@(VAN|DE?([NR])) } 
echo "$line" 

通過在最後一行雙引號$ line,您可以看到空格是否被正確刪除。

+0

'需要'是一個強詞。 Imo它不需要在這裏使用'extglob' – hek2mgl

+0

@ hek2mgl:爲了使用'@(... | ...)',你需要... – choroba

+0

呃你,是對的,我忽略了,因爲它是默認情況下在我的盒子上啓用..謝謝! – hek2mgl

0

使用awk:

echo $line | awk '{ if ($2 == "VAN" || $2 == "DEN" || $2 =="DE" || $2=="DER" ) $2=""; if ($3 == "VAN" || $3== "DEN" || $3 =="DE" || $3=="DER" ) $3="" ; print }' 
相關問題