2

我有两个文件,我使用下面的代码将它们基于密钥合并

file1
-------------------------------
1      a      t      p      bbb  
2      b      c      f      aaa  
3      d      y      u      bbb  
2      b      c      f      aaa  
2      u      g      t      ccc  
2      b      j      h      ccc

file2
--------------------------------
1   11   bbb  
2   22   ccc  
3   33   aaa  
4   44   aaa  

我使用下面的代码合并了这两个基于文件的密钥

awk 'NR==FNR{a[$3]=$0;next;}{for(x in a){if(x==$5) print $1,$2,$3,$4,a[x]};  

我的问题是如何在变量或数组中保存 $2 的 file2 并在 a[x] 之后再次打印。
我想要的结果是:

1 a t p 1   11  bbb  11  
2 b c f 3   33  aaa  33  
2 b c f 4   44  aaa  44  
3 d y u 1   11  bbb  11  
2 b c f 3   33  aaa  33  
2 b c f 4   44  aaa  44  
2 u g t 2   22  ccc  22  
2 b j h 2   22  ccc  22  

如您所见,前 7 列是我的合并代码的结果。我需要将最后一列(a[x] 的字段 2)添加到我的结果中。

重要的:

我的下一个问题是如果我有 .awk 文件,我如何使用一些 bash 脚本代码(如(| column -t)或将结果发送到文件(awk... > result.txt)?我总是在命令提示符下使用这些代码。我可以在 .awk 文件的代码中使用它们吗?

4

3 回答 3

3

您当前的脚本是:

awk 'NR==FNR { a[$3]=$0; next }
             { for (x in a) { if (x==$5) print $1,$2,$3,$4,a[x] } }'

(实际上,原版缺少第二个模式/动作对的第二个右括号。)

似乎您在处理file2之前先处理file1

您不应该需要第二个代码中的循环。通过在第一阶段使用拆分来保持所需的值,您可以让自己的生活更轻松:

awk 'NR==FNR { c1[$3] = $1; c2[$3] = $2; next }
             { print $1, $2, $3, $4, c1[$5], c2[$5], $5, c2[$5] }'

您可以对其进行升级以检查c1[$5]和是否c2[$5]已定义,如果未定义,则可能会跳过该行。

给定您的输入文件,输出为:

1 a t p 1 11 bbb 11
2 b c f 4 44 aaa 44
3 d y u 1 11 bbb 11
2 b c f 4 44 aaa 44
2 u g t 2 22 ccc 22
2 b j h 2 22 ccc 22

给予或采用列间距,这就是所要求的。列间距可以通过使用printf而不是来固定print,或者将 OFS 设置为制表符,或者...

第1 列和第 2 列的c1andc2符号对于两列是可以的。如果您需要更多,那么您可能应该使用 2D 数组表示法:

awk 'NR==FNR { for (i = 1; i <= NF; i++) col[i,$3] = $i; next }
             { print $1, $2, $3, $4, col[1,$5], col[2,$5], $5, col[2,$5] }'

这会产生与以前相同的输出。

于 2012-10-15T23:16:55.613 回答
3

只需将所有的添加file2到一个数组中,并使用split来保存您想要的位:

awk 'FNR==NR { two[$0]++; next } { for (i in two) { split(i, one); if (one[3] == $NF) print $1,$2,$3,$4, i, one[2] } }' file2 file1

结果:

1 a t p 1   11   bbb   11
2 b c f 3   33   aaa   33
2 b c f 4   44   aaa   44
3 d y u 1   11   bbb   11
2 b c f 3   33   aaa   33
2 b c f 4   44   aaa   44
2 u g t 2   22   ccc   22
2 b j h 2   22   ccc   22

关于你的最后一个问题;您还可以在awk. 这是一个管道示例column -t

内容script.awk

FNR==NR { 
    two[$0]++
    next
}

{
    for (i in two) {
        split(i, one)
        if (one[3] == $NF) { 
            print $1,$2,$3,$4, i, one[2] | "column -t"
        }
    }
}

像这样运行:awk -f script.awk file2 file1

编辑:

将以下内容添加到您的 shell 脚本中:

results=$(awk '

    FNR==NR {
        two[$0]++
        next
    }

    {
        for (i in two) {
            split(i, one)
            if (one[3] == $NF) {
                print $1,$2,$3,$4, i, one[2] | "column -t"
            }
        }
    }
' $1 $2)

echo "$results"

像这样运行:

./script.sh file2.txt file1.txt

结果:

1  a  t  p  1  11  bbb  11
2  b  c  f  3  33  aaa  33
2  b  c  f  4  44  aaa  44
3  d  y  u  1  11  bbb  11
2  b  c  f  3  33  aaa  33
2  b  c  f  4  44  aaa  44
2  u  g  t  2  22  ccc  22
2  b  j  h  2  22  ccc  22
于 2012-10-15T23:21:39.670 回答
2

要实现您的要求,请在处理第一个文件的整行之后保存第二个字段,使用a[$3]=$0 OFS $2. 对于您的第二个问题,awk有一个变量来分隔输出中的字段,它是OFS,为其分配一个制表符并使用它。你的脚本会是这样的:

awk '
    BEGIN { OFS = "\t"; } 
    NR==FNR{
        a[$3]=$0 OFS $2;
        next;
    }
    {
        for(x in a){
            if(x==$5) print $1,$2,$3,$4,a[x]
        } 
    }
' file2 file1

这会产生:

1       a       t       p       1   11   bbb    11
2       b       c       f       4   44   aaa    44
3       d       y       u       1   11   bbb    11
2       b       c       f       4   44   aaa    44
2       u       g       t       2   22   ccc    22                                                                                                                                                                                           
2       b       j       h       2   22   ccc    22
于 2012-10-15T22:30:20.797 回答