2014-03-18 30 views
3

我正在編寫腳本來處理文本文件。BASH - 判斷是否存在重複行(y/n)

我想要做的第一件事是檢查是否存在重複的條目,如果是,請詢問用戶是否要保留或刪除它們。

我知道如何顯示重複的行,如果它們存在,但我想要學習的只是對「存在重複嗎?」這個問題得到肯定/否定的答案。

看起來uniq將返回0要麼重複發現或沒有找到重複只要命令完成沒有問題。

我可以在if -statement中輸入什麼命令來告訴我是否存在重複行?

我的文件很簡單,它只是單列中的值。

+0

如果你不反對使用Vim進行人工過濾的文本文件,我建議在http://stackoverflow.com/questions/1268032的'HighlightRepeats'方法。我經常用它來過濾重複的文件/文件夾,然後在過濾的文件上應用shell命令。 –

+1

@ F.X感謝您的回覆。我想用腳本中的一些行來完成此操作。 – DMS

回答

3

您可以使用awk與布爾||運營商合併:

# Ask question if awk found a duplicate 
awk 'a[$0]++{exit 1}' test.txt || (
    echo -n "remove duplicates? [y/n] " 
    read answer 
    # Remove duplicates if answer was "y" . I'm using `[` the shorthand 
    # of the test command. Check `help [` 
    [ "$answer" == "y" ] && uniq test.txt > test.uniq.txt 
) 

||後,該塊將只能得到,如果awk命令返回1執行,這意味着它發現重複。

然而,一個基本的瞭解,我會還使用if

awk 'a[$0]++{exit 1}' test.txt 

# $? contains the return value of the last command 
if [ $? != 0 ] ; then 
    echo -n "remove duplicates? [y/n] " 
    read answer 
    # check answer 
    if [ "$answer" == "y" ] ; then 
     uniq test.txt > test.uniq.txt    
    fi 
fi 

顯示一個例子。然而[]只是括號像其他編程語言。 [test bash內建命令的同義詞,]是最後一個參數。您需要以瞭解閱讀help [

+0

感謝您的幫助。我會嘗試一下你的代碼。 – DMS

1

您可以使用此AWK一行代碼做uniq=yes/no

awk '!seen[$0]{seen[$0]++; i++} END{print (NR>i)?"no":"yes"}' file 
  • awk中使用的唯一身份稱爲seen的數組。
  • 每次我們把一個元素放在一個唯一的元素中,我們增加一個計數器i++
  • 最後在END塊,我們比較的記錄#與本守則獨特記錄#:(NR>i)?
  • 如果條件爲真,這意味着有重複的記錄,我們打印no否則打印yes
+0

感謝您的回覆。你能向我解釋你的線路是如何工作的嗎? – DMS

+0

是的確定添加了解釋。 – anubhava

1

快速bash的解決方案:

#!/bin/bash 

INPUT_FILE=words 

declare -A a 
while read line ; do 
    [ "${a[$line]}" = 'nonempty' ] && duplicates=yes && break 
    a[$line]=nonempty 
done < $INPUT_FILE 

[ "$duplicates" = yes ] && echo -n "Keep duplicates? [Y/n]" && read keepDuplicates 

removeDuplicates() { 
    sort -u $INPUT_FILE > $INPUT_FILE.tmp 
    mv $INPUT_FILE.tmp $INPUT_FILE 
} 

[ "$keepDuplicates" != "Y" ] && removeDuplicates 

腳本從INPUT_FILE並存儲關聯數組a爲重點,在每一行逐行地讀取並設置字符串作爲價值的nonempty。在存儲該值之前,它首先檢查它是否已經存在 - 如果是這意味着它發現重複並且它設置duplicates標誌,然後突破該週期。

後來它只檢查標誌是否設置並詢問用戶是否保留重複項。如果他們回答Y以外的任何內容,則它會調用removeDuplicates函數,該函數使用sort -u刪除重複項。 ${a[$line]}評估爲關鍵字$line的關聯數組a的值。 [ "$duplicates" = yes ]是用於測試的bash內建語法。如果測試成功,則在&&之後進行評估。

但請注意,awk解決方案可能會更快,所以如果您希望處理更大的文件,您可能需要使用它們。

+0

謝謝jkbkot!你可以給我一個關於這個代碼如何工作的簡要說明嗎?我是菜鳥:) – DMS

+0

@DMS沒問題,補充說明。順便說一句,upvoting是不夠的,謝謝;),也嘗試接受其中的一個答案,以保持網站的組織。快樂的編碼! –

5

我可能會使用awk要做到這一點,但對於不同的緣故,這裏是一個簡短的管道完成同樣的事情:

$ { sort | uniq -d | grep . -qc; } < noduplicates.txt; echo $? 
1 
$ { sort | uniq -d | grep . -qc; } < duplicates.txt; echo $? 
0 

sort + uniq -d確保只有重複的行(這不必相鄰)打印到stdoutgrep . -c計算那些仿效wc -l的行,如果它不匹配(即零計數)並且-q只是使輸出保持靜默,那麼它不會產生有用的副作用,它會返回1,打印行數,以便您可以在腳本中靜靜地使用它。

has_duplicates() 
{ 
    { 
    sort | uniq -d | grep . -qc 
    } < "$1" 
} 

if has_duplicates myfile.txt; then 
    echo "myfile.txt has duplicate lines" 
else 
    echo "myfile.txt has no duplicate lines" 
fi 
相關問題