2016-09-26 90 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)) 
相关问题