自然使用AWK,Join等在unix中的两个文件之间加入

时间:2018-03-18 08:09:03

标签: linux unix join awk

FILE_A

1 MIR6859-1 2340    DDX11L1 3222
2 MIR6859-1 4860    WASH7P  7074
3 WASH7P    326 MIR1302-2   670
4 FAM138A   15  MIR1302-2   5730
8 LOC729737 7270    OR4F5   64205  LOC123 764  LOC125 783
9 LOC729737 3070    OR4F5   68405
10 LOC729737    88330   LOC100132287    94996 LOC7  883
11 LOC100132287 86996   LOC729737   96330
12 LOC100132287 80196   LOC729737   103130
13 LOC100132287 72396   LOC729737   110930
14 LOC100132287 61196   LOC729737   122130
15 LOC100132287 56596   LOC729737   126730 TYUI 678
40 QWER 456

FILE_B

join -a1 file_a file_b

和期望的输出是

paste file_a file_b

所以基本上这是基于两个文件中第一列相等的自然连接。

我在搜索网页后尝试了各种命令 -

ldapmodify

{{1}}

但没有得到理想的输出。

3 个答案:

答案 0 :(得分:1)

awk 解决方案:

awk 'NR == FNR{ a[$1] = ($1 in a? a[$1] OFS : "")$2 OFS $3; next }
     $1 in a{ $0 = $0 OFS a[$1]; delete a[$1] }1;
     END{ for (i in a) print i, a[i] }' file_b file_a

输出:

1 MIR6859-1 2340    DDX11L1 3222
2 MIR6859-1 4860    WASH7P  7074
3 WASH7P    326 MIR1302-2   670
4 FAM138A   15  MIR1302-2   5730
8 LOC729737 7270    OR4F5   64205 LOC123 764 LOC125 783
9 LOC729737 3070    OR4F5   68405
10 LOC729737    88330   LOC100132287    94996 LOC7 883
11 LOC100132287 86996   LOC729737   96330
12 LOC100132287 80196   LOC729737   103130
13 LOC100132287 72396   LOC729737   110930
14 LOC100132287 61196   LOC729737   122130
15 LOC100132287 56596   LOC729737   126730 TYUI 678
40 QWER 456

答案 1 :(得分:1)

关注awk也可以帮助您。

awk 'FNR==NR{val=$1;$1="";sub(/^ +/,"");a[val]=a[val]?a[val] OFS $0:$0;next} {print $0,a[$1]}' FIle_b  FIle_a

现在也添加非单线形式的解决方案。

awk '
FNR==NR{
  val=$1;
  $1="";
  sub(/^ +/,"");
  a[val]=a[val]?a[val] OFS $0:$0;
  next}
{
  print $0,a[$1]}
' FIle_b  FIle_a

说明: 此处也添加了代码说明。

awk '
FNR==NR{                         ##FNR==NR is a condition which is TRUE only when first Input_file named FIle_b in this case is being read. Do following in case of this condition is TRUE.
  val=$1;                        ##Creating variable val whose value is first field of the current line.
  $1="";                         ##Nullifying the first field value in current line.
  sub(/^ +/,"");                 ##Using sub out of the box utility of awk here to substitute initial space with NULL here on current line.
  a[val]=a[val]?a[val] OFS $0:$0;##Creating an array named a whose index is variable val and it concatenates its own value in it too. to cover all duplicates in file.
  next}                          ##next is awk out of the box keyword which will skip all further lines from here.
{
  print $0,a[$1]}                ##This print statement will only execute when 2nd Input_file is being read and it prints current line along with that value of araay a whose index is first field of array a.
' FIle_b  FIle_a                 ##Mentioning Input_file(s) here, first Input_file is FIle_b and second Input_file is FIle_a.

答案 2 :(得分:0)

我想补充一些评论,澄清此事:

1)联接字段在file_b

中重复
8 LOC123 764
...
8 LOC125 783

在数据库中的“真实”连接中,这将产生两行输出

8 LOC729737 7270    OR4F5   64205  LOC123 764  
8 LOC729737 7270    OR4F5   64205  LOC125 783

不是你想要的串联:

8 LOC729737 7270    OR4F5   64205 LOC123 764 LOC125 783

因此,说你想加入是错误的。

2)即使没有重复的行,也会是全外连接,而不是自然连接,因为你想要来自两个来源的所有不成对的行。 / p>

3)paste不起作用,因为它只在两个文件中将行与相应的行号配对,它不知道 join field 的概念。

4)join(unix命令)不起作用,不仅因为它想要通过连接字段排序的输入文件(这很容易提供),而且因为它不支持完全外连接:选项-a1执行左外连接(包括来自第一个源的无法使用的线),选项-a2执行右外连接(包括来自第二个源的不可用线),但是同时使用这两个选项需要进一步选择--nocheck-order并生成一些不是完全外连接的东西。

5)那就是说,我也提供了一个awk解决方案,它比目前提供的解决方案短,并产生相同的输出:

awk '{k=$1;sub("^"k,"");a[k]=a[k] OFS $0}
     END{for(k in a)print k a[k]|"sort -k1,1n"}' file_a file_b

6)如果输出字段之间的空白量不重要,您也可以使用较短的

awk '{k=$1;$1="";a[k]=a[k] $0}
     END{for(k in a)print k a[k]|"sort -k1,1n"}' file_a file_b