比较文件的awk,打印匹配并连接,如果有不止一个匹配
你好,我有这两个文件:比较文件的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 ...
您可以使用此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
在第二个文件中存在araya
-
print $1, ($1 in a ? a[$1] : 0
- 打印$1
和数组的值如果$1
在a
否则为0将打印。
完美的功能!谢谢!请问您可以添加一个简短的解释吗? – user3666956
我在答案中添加了解释。 – anubhava
你可以使用这样的事情:
$ 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
并打印。
太棒了!你能否添加一个简短的解释? – user3666956
@ user3666956:添加了一个小解释。让我知道你有没有什么不清楚的地方。 – user000001
Thx,现在对我来说很清楚! – user3666956
随着空白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
语句
下面是使用join
,uniq
不可阻挡的思考过程的产物, tac
,grep
和sort
。我们的想法是获取唯一的键值对(特别是对于键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))
要追加到[$ 1]不能覆盖它。 – 123
以'1712'开头的行输出缺少'0.989011' – anubhava