使用两个文件时在AWK中使用数组

时间:2012-10-15 22:17:18

标签: awk

我有两个文件,我使用下面的代码

基于密钥合并它们
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并再次在[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列是我的合并代码的结果。我需要将最后一列([x]的字段2)添加到我的结果中。

重要的:

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

3 个答案:

答案 0 :(得分: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列的c1c2符号对于两列是正常的。如果您需要更多,那么您应该使用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] }'

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

答案 1 :(得分: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

答案 2 :(得分: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