在循环期间重新分配awk数组

时间:2017-02-10 14:32:04

标签: arrays bash awk

我的问题如下: 我有一个格式化的文本文件:

12 apple 
78 orange 
12 prune
12 prune
78 berries
78 cake

我需要的是以表格形式重新分配值:

12 apple, prune
78 orange, berries, cake

我使用awk {sbj=$2","; a[$1]=a[$1]sbj}END{for (i in a) print i, a[i]}做到了 但问题是现在我有了这个文件,格式为:

12 apple one
78 orange one

12 prune two
12 prune two
78 berries two
78 cake two

欲望输出是:

12 apple one
78 orange one

12 prune two
78 berries, cake two

我试图混合awk和bash,但它没有帮助。我现在能做的唯一选择是将每个系列("一个","两个")存储到单独的文件中,并使用上面的代码单独处理它们,然后将所有数组汇总到一份文件。但这是一个笨重而笨拙的解决方案。有没有选项让它在同一个文件中? 谢谢你的任何提示。

2 个答案:

答案 0 :(得分:4)

$ cat tst.awk
NF {
    if (!seen[$1,$2]++) {
        arr[$1] = ($1 in arr ? arr[$1] "," OFS : "") $2
        sfx[$1] = $3
    }
    next
}
{ prt() }
END { prt() }

function prt(   i) {
    for (i in arr) {
        print i, arr[i], sfx[i]
    }
    print ""
    delete sfx
    delete arr
    delete seen
}

$ awk -f tst.awk file
12 apple one
78 orange one

12 prune two
78 berries, cake two

请注意,上面将以in运算符的随机顺序打印输出行 - 如果要保留原始输入顺序,则在保存值时需要额外的步骤。然而,它将按照它们在输入中出现的顺序打印块和$ 2值。

答案 1 :(得分:1)

使用GNU awk,您可以使用多维数组:

foo.awk:

!NF{next} # Skip empty lines
{a[$3][$1]=a[$3][$1]" "$2}
END{
    for(i in a){
        for(ii in a[i]){
            print ii" "a[i][ii]" "i
        }
        print ""
    }
}

像以下一样运行:

gawk -f foo.awk input.file

我需要提一下上述解决方案有一个缺点,除了它只适用于gawk:输出不保证按顺序排列。那是因为for(i in a)默认不保证任何订单。 gawk支持一个特殊的数组变量PROCINFO,可用于强制对数组进行单独排序:

foo.awk:

BEGIN {
    PROCINFO["sorted_in"] = "@ind_str_asc"
}
!NF{next} # Skip empty lines
{a[$3][$1]=a[$3][$1]" "$2}
END{
    for(i in a){
        for(ii in a[i]){
            print ii" "a[i][ii]" "i
        }
        print ""
    }
}