鉴于此示例输入:
ID Sample1 Sample2 Sample3 One 10 0 5 Two 3 6 8 Three 3 4 7
我需要使用AWK生成此输出:
ID Sample1 Sample2 Sample3 One 62.50 0.00 25.00 Two 18.75 60.00 40.00 Three 18.75 40.00 35.00
这就是我解决它的方法:
function percent(value, total) {
return sprintf("%.2f", 100 * value / total)
}
{
label[NR] = $1
for (i = 2; i <= NF; ++i) {
sum[i] += col[i][NR] = $i
}
}
END {
title = label[1]
for (i = 2; i <= length(col) + 1; ++i) {
title = title "\t" col[i][1]
}
print title
for (j = 2; j <= NR; ++j) {
line = label[j]
for (i = 2; i <= length(col) + 1; ++i) {
line = line "\t" percent(col[i][j], sum[i])
}
print line
}
}
这在GNU AWK中很好用(Linux中为awk
,BSD中为gawk
),
但不是在BSD AWK中,我收到此错误:
$ awk -f script.awk sample.txt awk: syntax error at source line 7 source file script.awk context is sum[i] += >>> col[i][ <<< awk: illegal statement at source line 7 source file script.awk awk: illegal statement at source line 7 source file script.awk
似乎问题在于多维数组。 我想让这个脚本也在BSD AWK中运行, 所以它更便携。
有没有办法更改它以使其在BSD AWK中工作?
答案 0 :(得分:4)
尝试使用伪二维形式。而不是
col[i][NR]
使用
col[i,NR]
这是一维数组,关键是连接字符串:i SUBSEP NR
答案 1 :(得分:3)
@glenn的回答让我走上了正确的道路。虽然花了更多的工作:
col[i, NR]
处理列标题很麻烦。它有助于删除列标题的缓冲并在阅读后立即打印它们length(col) + 1
在最终循环条件中不再可用,因为使用col[i, j]
使循环无限。作为解决方法,我可以使用length(col) + 1
NF
这是最终的实现,现在可以在AWK的GNU和BSD版本中使用:
function percent(value, total) {
return sprintf("%.2f", 100 * value / total)
}
BEGIN { OFS = "\t" }
NR == 1 { gsub(/ +/, OFS); print }
NR != 1 {
label[NR] = $1
for (i = 2; i <= NF; ++i) {
sum[i] += col[i, NR] = $i
}
}
END {
for (j = 2; j <= NR; ++j) {
line = label[j]
for (i = 2; i <= NF; ++i) {
line = line OFS percent(col[i, j], sum[i])
}
print line
}
}