2016-07-09 38 views
1

我正在從zsh切換到bash,並且我需要生成一個bash腳本,可以刪除$PATH中的重複條目,而不用重新排序條目(因此沒有sort -d魔法)。 zsh有一些不錯的數組處理快捷方式,可以很容易地做到這一點,但我不知道bash中的這種快捷方式。我遇到了this answer,這讓我有90%的途徑在這裏,但有一個小問題我想更好地理解。看來,當我運行awk命令時,最後處理的記錄不正確地匹配模式。awk模式總是匹配最後一條記錄?

$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc" 
aa:bb:cc:cc 
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb" 
aa:bb:cc:bb 
$ awk 'BEGIN{RS=ORS=":"}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:" # note trailing colon 
aa:bb:cc: 

我不明白AWK不夠好,知道爲什麼它的行爲這樣,但我已經設法通過使用中間陣列,像這樣以解決此問題。

array=($(awk 'BEGIN{RS=":";ORS=" "}!a[$0]++' <<<"aa:bb:cc:aa:bb:cc:")) 
# Use a subshell to avoid modifying $IFS in current context 
echo $(export IFS=":"; echo "${array[*]}") 
aa:bb:cc 

這似乎是一個次優解但是,所以我的問題是:我做錯了什麼在導致最終記錄誤報匹配處理awk命令?

回答

4

原始字符串中的最後一條記錄是cc\n,與cc不同。當不確定發生了什麼事,在任何語言的任何程序,增加了一些打印語句是第1步調試/調查:

$ awk 'BEGIN{RS=ORS=":"} {print "<"$0">"}' <<<"aa:bb:cc:aa:bb:cc" 
<aa>:<bb>:<cc>:<aa>:<bb>:<cc 
>:$ 

如果你想在RS是:\n那麼就至少聲明(與GNU AWK ):

$ awk 'BEGIN{RS="[:\n]"; ORS=":"} !a[$0]++' <<<"aa:bb:cc:aa:bb:cc" 
aa:bb:cc:$ 

$以上所有的都是我的提示。

+0

很好的例子,看看發生了什麼。但是你能解釋爲什麼一個新行被添加到字符串中嗎? –

+2

這是bash正在做的事情,它實質上使'cmd <<<「字符串」行爲與echo「字符串」行爲相同「。 cmd',但沒有額外的命令('echo')和管道。 POSIX文本處理工具(sed,awk,grep等)只能保證在POSIX文本文件上工作,否則會得到未定義的行爲,所以如果文件或輸入流不以換行符結束,那麼它不是POSIX文本文件/流,以便尾隨換行符是產生預期/期望行爲所必需的。 –

+1

謝謝!現在我對問題的原因有了更好的理解,這使我更接近於爲問題制定適當的解決方案。雖然這可能是一個小問題,但您的回答對我非常有幫助。 – Christopher

0

另一種可能的解決方法,而不是你的bash陣列的解決方案

$ echo "aa:bb:cc:aa:bb:cc" | tr ':' '\n' | awk '!a[$0]++' | paste -sd: 
aa:bb:cc