awk 按列将所有行除以另一行

awk 按列将所有行除以另一行

我试图将 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如果您将来也想打印列标题,则使用可能仍然会有所帮助。

相关内容