2008-12-17 95 views
114

我確定我曾經發現一個可以打印兩個或多個文件的公用行的unix命令,有人知道它的名字嗎?這比diff簡單得多。Unix命令查找兩個文件中常見的行

+5

這個問題的答案不一定是每個人都會想要的,因爲`comm`需要排序的輸入文件。如果你只需要一行一行的話,那很棒。但是如果你想要我所謂的「反差異」,「comm」就不能完成這項工作。 – 2012-04-20 14:15:55

+0

@ RobertP.Goldman當file1包含像pr-123-xy-45`這樣的部分模式,並且file2包含`ec11_orop_pr-123-xy-45.gz`時,有兩種方法可以在兩個文件之間獲得共同性。我需要file3包含`ec11_orop_pr-123-xy-45.gz` – 2015-11-02 07:20:51

回答

134

您正在尋找的命令是comm。例如: -

comm -12 1.sorted.txt 2.sorted.txt 

這裏:

-1:抑制第1欄(行特有1.sorted.txt)

-2:抑制第2欄(行特有2.sorted.txt)

+25

典型用法:comm -12 1.sorted.txt 2.sorted.txt – 2013-06-11 15:54:24

+20

雖然comm需要排序的文件,但您可以使用grep -f file1 file2來獲取兩個文件的共同行。 – ferdy 2015-01-20 17:29:00

+2

@ferdy(重複我的評論從你的答案,因爲你的本質是一個重複的答案張貼爲評論)`grep`做一些奇怪的事情,你可能不會指望。具體來說,`1.txt`中的所有內容都將被解釋爲一個正則表達式,而不是一個普通的字符串。另外,`1.txt`中的任何空行都會匹配`2.txt`中的所有行。所以`grep`只能在非常特殊的情況下工作。你至少要使用`fgrep`(或`grep -f`),但空行可能會對這個過程造成嚴重破壞。 – 2015-07-22 14:08:34

24

也許你的意思是comm

逐行比較排序文件FILE1和FILE2。

沒有選項,會產生三列輸出。第一列 包含FILE1特有的行,第 列包含第 FILE2特有的行,第3列包含兩個文件共有的行。

找到這些信息的祕訣就是信息頁面。對於GNU程序,它們比他們的手冊頁更詳細。嘗試info coreutils,它會列出你所有的小實用程序。

7
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2 
-2
rm file3.txt 

cat file1.out | while read line1 
do 
     cat file2.out | while read line2 
     do 
       if [[ $line1 == $line2 ]]; then 
         echo $line1 >>file3.out 
       fi 
     done 
done 

這應該這樣做。

2

僅供參考,如果有人還在尋找如何做到這一點的多個文件,查看鏈接答案Finding matching lines across many files.


這兩個答案(ans1ans2)結合,我覺得你可以得到導致你需要不排序的文件:

#!/bin/bash 
ans="matching_lines" 

for file1 in * 
do 
    for file2 in * 
     do 
      if [ "$file1" != "$ans" ] && [ "$file2" != "$ans" ] && [ "$file1" != "$file2" ] ; then 
       echo "Comparing: $file1 $file2 ..." >> $ans 
       perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' $file1 $file2 >> $ans 
      fi 
     done 
done 

只需保存它,給它執行權限(chmod +x compareFiles.sh)並運行它。它將採用當前工作目錄中的所有文件,並在「matching_lines」文件中進行全部比較。

事情還有待提高:

  • 跳過目錄
  • 避免比較所有文件的兩倍(文件1 VS文件2和file2 VS文件1)。
  • 也許行號添加下一個匹配的字符串
40

容易地把所述通訊命令無序文件,使用bash的process substitution

$ bash --version 
GNU bash, version 3.2.51(1)-release 
Copyright (C) 2007 Free Software Foundation, Inc. 
$ cat > abc 
123 
567 
132 
$ cat > def 
132 
777 
321 

所以文件ABC和DEF有一條共同之處,那就是「132」。 對未排序文件使用通訊

$ comm abc def 
123 
    132 
567 
132 
    777 
    321 
$ comm -12 abc def # No output! The common line is not found 
$ 

最後一行沒有產生輸出,普通線並沒有發現。

現在使用COMM上排序的文件,與進程替換排序文件:

$ comm <(sort abc) <(sort def) 
123 
      132 
    321 
567 
    777 
$ comm -12 <(sort abc) <(sort def) 
132 

現在我們得到了132線!

20

爲了補充Perl的一個班輪,這裏是它的awk相當於:

awk 'NR==FNR{arr[$0];next} $0 in arr' file1 file2 

這將讀取file1所有線路,陣列arr[],然後在file2檢查每一行,如果它已經內的存在陣列(即file1)。找到的行將按照它們在file2中出現的順序進行打印。 請注意,比較in arr使用從file2開始的整行作爲數組的索引,因此它只會報告整行上的完全匹配。

10

雖然

grep -v -f 1.txt 2.txt > 3.txt 

爲您提供了兩個文件的差異(什麼是2.txt而不是在1.txt的),你可以很容易地做一個

grep -f 1.txt 2.txt > 3.txt 

收集所有常見行,這應該爲您的問題提供一個簡單的解決方案。如果你有排序的文件,你應該採取comm。問候!

2

在Linux上的有限版本(如QNAP(NAS)我工作):
- 通訊不存在
- grep -f file1 file2可能會導致一些問題,如@ChristopherSchultz說,用grep -F -f file1 file2是很慢(更不到5分鐘 - 未完成了它 - 在2-3秒以下的文件的方法,超過20MB)

因此,這裏是我做過什麼:

sort file1 > file1.sorted 
sort file2 > file2.sorted 

diff file1.sorted file2.sorted | grep "<" | sed 's/^< *//' > files.diff 
diff file1.sorted files.diff | grep "<" | sed 's/^< *//' > files.same.sorted

如果「files.same。排序」應已在同一順序比原來的,比對同一訂單中加入這一行不是文件1:

awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file1 > files.same

,或者對同一訂單比file2:

awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file2 > files.same

4
awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2 
1

如果這兩個文件尚未排序,您可以使用:

comm -12 <(sort a.txt) <(sort b.txt) 

它會工作,避免錯誤信息comm: file 2 is not in sorted order comm -12 a.txt b.txt時。