我试图将 file1.txt 中的所有行除以 file2.txt 中单行中各自的(按列)值。
猫文件1.txt
1 2.5 3
7 7 7
1 3 5
猫文件2.txt
1 3 5
按照这个问题的建议解决方案:https://stackoverflow.com/questions/44908195/awk-multiplication-of-all-rows-in-a-table-with-first-row-of-the-table,我想出了以下代码:
cat file2.txt file1.txt | awk 'NR==1{split($0,m);CONVFMT="%.5f\t";next} {for (i=1;i<=NF;i++) $i=$i/m[i]} 1'
但是,由于其中一行中的所有值都等于 1,并且 CONVFMT 不适用于整数,因此我的输出文件中的格式很混乱。为了解决这个问题,我正在考虑使用带有制表符分隔符的 printf 而不是 CONVFMT,但考虑到我的实际文件具有可变数量的列,我不想要使用 $1、$2 等的硬编码解决方案。我不是精通 awk 所以我自己无法完全想出解决办法。
预先非常感谢您的帮助!
编辑:输出中的所有数字应格式化为 %.5f。
答案1
如果您希望所有字段的格式为%.5f
,您可以使用sprintf
:
BEGIN {
OFS = "\t"
}
NR == 1 {
cols = split($0,m)
next
}
NF == cols {
for (i=1; i<=NF; i++)
$i = sprintf("%.5f", $i/m[i])
}
1
$ awk -f above.awk file2 file1
1.00000 0.83333 0.60000
7.00000 2.33333 1.40000
1.00000 1.00000 1.00000
上面的awk
程序不会警告可能的错误。你可以尝试:
NR == 1 {
cols = split($0,m)
for (i in m)
if (m[i] == 0)
err("field "i" is "m[i]"; division by zero is fatal", 1)
next
}
NF != cols {
err("found "NF" fields, expected "cols)
next
}
{
for (i in m)
$i = sprintf("%.5f", $i/m[i])
print
}
END {
exit errs
}
function err(msg, r) {
# Print message to stderr
# Leave non-zero exit status
# Optionally go to END
printf "%s - %s.\n", "error: line "FNR" in "FILENAME, msg | "cat >&2"
errs = 1
if (r) exit
}
另外,您可能需要检查每个字段是否都是数字:使 awk 对非数字产生错误;我可以确定 awk 变量的类型吗?
答案2
不幸的是,您的问题并不清楚所需的输出格式。
但是,作为一般规则,如果您想确保“表格式输出”,您可以尝试将结果通过管道传输到column
:
awk 'BEGIN{CONVFMT="%.5f"} FNR==NR{split($0,div);next} NR>FNR{for (i=1;i<=NF;i++) $i=$i/div[i];}1' file2.txt file1.txt | column -t
这将导致
1 0.83333 0.60000
7 2.33333 1.40000
1 1 1
对于您提供的示例输入。
作为旁注,cat
在处理文件时,您永远不需要使用awk
(或sed
等)
更新
我从您的编辑中看到,所有数字都表示为 5 位十进制浮点数。在这种情况下,@guest 的解决方案是正确的方法,尽管column
如果您将来也想打印列标题,则使用可能仍然会有所帮助。