簡體   English   中英

比較文件awk,打印匹配項,如果有多個匹配項,則串聯

[英]compare files awk, print matches and concatenate if there is more than one match

您好我有這兩個文件:

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

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

您可以使用以下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

參考: 有效的AWK編程 工作原理:

  • 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中的第2個文件存在於阿雷a
  • print $1, ($1 in a ? a[$1] : 0 -打印$1和從陣列如果值$1a否則0將被打印。

您可以使用如下形式:

$ 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塊中的next一條語句)。 如果找到匹配的行,則打印它,否則,將0連接到第一個單詞,然后打印。

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語句

這是使用joinuniqtacgrepsort進行的不可阻擋的思考過程的產物。 這樣做的想法是獲取唯一的鍵值對(尤其是鍵1712),並加入它們以避免出現諸如1708 1.000000 CG 1.000000 CG這樣的行,因此該解決方案將不支持將每個鍵組合成三個或更多的值。 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))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM