从不同的文件添加具有部分匹配模式的列

时间:2016-06-13 19:00:49

标签: bash terminal pattern-matching paste data-manipulation

我有两个结构相似的文件(制表符分隔,很多很多行,第3列减去第2列= 1),看起来有点像这样:

文件1:

1 170023 170024 A -
1 170024 170025 T -
1 170026 170027 A -
1 170028 170029 G -
1 170029 170030 C -
1 170031 170032 C -

文件2:

1 170023 170024 A
1 170024 170025 T
1 170025 170026 G
1 170026 170027 A
1 170027 170028 G
1 170028 170029 T
1 170029 170030 A
1 170030 170031 G
1 170031 170032 C

我想将文件2中的第4列(仅限字母列)添加到文件1.对于prpaste,这通常很容易,但问题是第1列-3在两个文件中不相同。换句话说,文件具有不同数量的行,文件2总是比文件1更多行(特别是,文件1中找到的第2和第3列中的所有数字也出现在文件2中,但不是反之亦然< / em>的)。我也知道如何在R中执行它但是文件太大而不能在R中轻松处理我将需要为十几个文件执行任务。所以我猜,bash或任何命令行软件都是最有效的解决方案。

我真正想要做的是添加文件2中第4列的字母,当且仅当文件2中的第1-3列完全匹配文件1中的第1-3列时。因此,文件1的第4列和第5列中出现的符号无关紧要。根据上面的文件1和文件2的示例,所需的输出将是:

输出:

1 170023 170024 A - A
1 170024 170025 T - T
1 170026 170027 A - A
1 170028 170029 G - T
1 170029 170030 C - A
1 170031 170032 C - C

如果有人可以帮助我,我会很高兴的。非常感谢你提前!

1 个答案:

答案 0 :(得分:1)

我可以考虑使用joinawk为此提供一个简单的解决方案。可能不是使用awk解决问题的最有效方法(可能会因此而被专家抨击:)),但我能够解决这个问题。

<强>解决方案-1: -

您需要做的就是首先使用join而不指定要加入的任何特定列。它会根据常见的重复列自动连接文件,在本例中为第1列。然后在该输出上,我们可以让awk播放打印符合您需要的行并格式化所需的列。

join file1 file2 | awk '{ if (($2==$6) && ($3==$7)) printf("%s %s %s %s %s %s\n", $1, $2, $3, $4, $5, $8) }'

将输出生成为

1 170023 170024 A - A
1 170024 170025 T - T
1 170026 170027 A - A
1 170028 170029 G - T
1 170029 170030 C - A
1 170031 170032 C - C

<强>解决方案-2: -

仅使用普通join

join -j 2 file1 file2 -o 1.1,1.2,1.3,1.4,1.5,2.4

也会产生与预期相同的输出。

`join' writes to standard output a line for each pair of input lines that have identical join fields.

引用man的{​​{1}}页面内容,如下所示

join

因此,该命令首先通过第2列加入`-j FIELD' Equivalent to `-1 FIELD -2 FIELD'. `-o FIELD-LIST' Otherwise, construct each output line according to the format in FIELD-LIST. Each element in FIELD-LIST is either the single character `0' or has the form M.N where the file number, M, is `1' or `2' and N is a positive field number. file1,然后从看到的输出中打印所需的列,由(file21.1,{表示{1}},1.21.31.4),应该被理解为1.52.4。为了更好地理解,我建议首先看一下没有file选项的输出,以及我是如何构建输出的。

<强>解决方案-3: -

使用plain'ol column,我在回答这个问题的时候实际上已经学会了一点。

-o

说明: -

  1. awk将在awk 'FNR==NR{a[$1 FS $2 FS $3]=$4;next} (($1 FS $2 FS $3) in a) {print $0, a[$1 FS $2 FS $3]}' file2 file1 上处理存储数组FNR==NR{a[$1 FS $2 FS $3]=$4;next}的条目,其下标为column1 space column2 space column3,value为column4。

  2. 现在在file2上,我们需要通过执行a来匹配数组中file1的那些行,这将为我提供所有这些行(我们需要column4的值)在file2中,其下标与(($1 FS $2 FS $3) in a) {print $0, a[$1 FS $2 FS $3]}中的一个相同。