2016-09-26 86 views
1

你好,我有這兩個文件:比較文件的awk,打印匹配並連接,如果有不止一個匹配

cat file1.tab 
1704 1.000000 T G 
1708 1.000000 C G 
1711 1.000000 G C 
1712 0.989011 T A 
1712 0.003564 T G 

cat file2.tab 
1704 
1705 
1706 
1707 
1708 
1709 
1710 
1711 
1712 
1713 

我想這樣的輸出:

1704 1.000000 T G 
1705 0 
1706 0 
1707 0 
1708 1.000000 C G 
1709 0 
1710 0 
1711 1.000000 G C 
1712 0.003564 T G 0.003564 T G 
1713 0 

我能幾乎得到它與此:

awk 'NR==FNR { a[$1]=$0;b[$1]=$1; next} { if ($1 == b[$1]) print a[$1]; else print $1,"0";}' file1.tab file2.tab 

但我不知道如何處理重複..我的腳本不檢查是否在第1列中的字符file1.tab是重複的,因此它輸出的只是它出現在最後一次$ 0 ...

+0

要追加到[$ 1]不能覆蓋它。 – 123

+0

以'1712'開頭的行輸出缺少'0.989011' – anubhava

回答

2

您可以使用此AWK:

awk 'FNR==NR{a[$1] = (a[$1]==""?"":a[$1] " ") $2 OFS $3 OFS $4; next} 
    {print $1, ($1 in a ? a[$1] : 0)}' file1 file2 

1704 1.000000 T G 
1705 0 
1706 0 
1707 0 
1708 1.000000 C G 
1709 0 
1710 0 
1711 1.000000 G C 
1712 0.989011 T A 0.003564 T G 
1713 0 

參考:Effective AWK Programming 工作原理:

  • FNR==NR - 執行此塊file1
  • a[$1] = (a[$1]==""?"":a[$1] " ") $2 OFS $3 OFS $4 - 創建關聯數組a與密鑰作爲$1和值作爲$2 + $3 + $4(保持附加前次值)
  • next - 跳到下一記錄
  • {...} - 執行該塊爲第二輸入文件file2
  • if ($1 in a)如果$1在第二個文件中存在aray a
  • print $1, ($1 in a ? a[$1] : 0 - 打印$1和數組的值如果$1a否則爲0將打印。
+1

完美的功能!謝謝!請問您可以添加一個簡短的解釋嗎? – user3666956

+1

我在答案中添加了解釋。 – anubhava

2

你可以使用這樣的事情:

$ awk 'NR==FNR{$1=$1 in a?a[$1]:$1;$0=$0;a[$1]=$0;next}{print $1 in a?a[$1]:$1 OFS 0}' file1.tab file2.tab 
1704 1.000000 T G 
1705 0 
1706 0 
1707 0 
1708 1.000000 C G 
1709 0 
1710 0 
1711 1.000000 G C 
1712 0.989011 T A 0.003564 T G 
1713 0 

一些解釋它是如何工作:

  • 此塊'NR==FNR{$1=$1 in a?a[$1]:$1;$0=$0;a[$1]=$0;next}在第一個文件,其中記錄索引等於執行文件記錄索引。因此,對於第一個文件,我們將第一個單詞設置爲存儲在數組中的值(如果存在),否則設置第一個單詞。然後,與$0=$0我們重新拆分字段,因爲第一個字段現在可能包含多個單詞。之後,我們將行存儲在數組中,使用第一個字作爲索引
  • {print $1 in a?a[$1]:$1 OFS 0}'僅對第二個文件的行執行(由於前一個塊中的next語句)。如果找到匹配的行,我們打印它,否則,我們將第一個字連接0並打印。
+0

太棒了!你能否添加一個簡短的解釋? – user3666956

+1

@ user3666956:添加了一個小解釋。讓我知道你有沒有什麼不清楚的地方。 – user000001

+0

Thx,現在對我來說很清楚! – user3666956

1

隨着空白perl

$ perl -F'/\s+/,$_,2' -lane ' 
    if(!$#ARGV){ $h{$F[0]} .= $h{$F[0]} ? " $F[1]" : $F[1] } 
    else{ print "$F[0] ", $h{$F[0]} ? $h{$F[0]} : 0 } 
    ' file1.tab file2.tab 
1704 1.000000 T G 
1705 0 
1706 0 
1707 0 
1708 1.000000 C G 
1709 0 
1710 0 
1711 1.000000 G C 
1712 0.989011 T A 0.003564 T G 
1713 0 
  • -F'/\s+/,$_,2'分割輸入線,最大2個字段
  • !$#ARGV將工作類似於AWK的NR==FNR兩個文件的命令行參數
  • %h散列變量保存基於第一個字段的附加值作爲密鑰
  • 當處理第二文件,打印爲每所需的格式從輸入線
  • -l選項條換行符,並增加了新行到每個print語句
0

下面是使用joinuniq不可阻擋的思考過程的產物, tacgrepsort。我們的想法是獲取唯一的鍵值對(特別是對於鍵1712)並加入這些鍵以避免像1708 1.000000 C G 1.000000 C G這樣的行,因此此解決方案不支持對每個鍵分組三個或更多個值。 join -o ... -e "0"也不會在非連接行上生成1 0,因爲file1.tab有3列要加入。

$ join -a 1 <(join -a 1 file2.tab <(uniq -w 4 file1.tab)) <(grep -v -f <(uniq -w 4 file1.tab) <(tac file1.tab|uniq -w 4|sort)) 
1704 1.000000 T G 
1705 
1706 
1707 
1708 1.000000 C G 
1709 
1710 
1711 1.000000 G C 
1712 0.989011 T A 0.003564 T G 
1713 

更加結構化的佈局:

$ join -a 1 
      <(join -a 1 
         file2.tab 
         <(uniq -w 4 file1.tab)) 
      <(grep -v -f 
         <(uniq -w 4 file1.tab) 
         <(tac file1.tab|uniq -w 4|sort)) 
相關問題