0

I'm trying to divide all lines in file1.txt by their respective (column-wise) value in the single line in file2.txt.

cat file1.txt

1       2.5     3
7       7       7
1       3       5

cat file2.txt

1   3   5

Following the suggested solution for this question: https://stackoverflow.com/questions/44908195/awk-multiplication-of-all-rows-in-a-table-with-first-row-of-the-table, I came up with the following code:

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'

However, since all values in one of the rows equal 1, and CONVFMT doesn't work on integers, the format in my output file is messed up. To fix this, I was thinking on using printf with tab separator instead of CONVFMT, but given that my actual files have a variable number of columns, I don't want a hard coded solution using $1, $2, etc. I'm not proficient in awk so I can't quite come up with a fix on my own.

Thank you very much in advance for your help!

Edit: all numbers in output should be formatted as %.5f.

1
  • 1
    Welcome to the site. Can you edit your post to specify the desired output for the sample input you provided? Is it "5 decimals for fractions, none for integers"?
    – AdminBee
    Apr 23, 2020 at 13:22

2 Answers 2

2

If you want all fields formatted as %.5f, you could use 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

The above awk program doesn't warn about possible errors. You could try:

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
}

Also, you may want to check that each field is a number: Make awk produce error on non-numeric; Can I determine type of an awk variable?

3
  • Thank you very much, this is exactly what I wanted and works perfectly! :)
    – Arynio
    Apr 23, 2020 at 13:57
  • 2
    Just a suggestion to do an error check rather than just ignore any mismatches NF!=cols{ print "Wrong number of fields at row "FNR" in "FILENAME; next}{for (i=1; i<=NF; i++)
    – bu5hman
    Apr 23, 2020 at 15:45
  • 2
    It might be worth checking for m[i] being non-zero before dividing by it. Also print > "/dev/stderr" will only work in some awks, print | "cat>&2" will work in all of them.
    – Ed Morton
    Apr 24, 2020 at 0:13
1

Unfortunately, the desired output format is not quite clear from your question.

However, as a general rule, if you want to ensure "table-formatted output", you could try piping the result to 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

which will result in

1  0.83333  0.60000
7  2.33333  1.40000
1  1        1

for the sample input you provided.

As a side note, you never need to use cat when processing files with awk (or sed etc.)

Update

I see from your edit that all numbers are to represented as 5-decimal floating-point numbers. In that case, the solution by @guest is the right way, although the use of column may still be helpful if at any time in the future you want to print column titles, too.

1
  • Thank you very much, I can confirm it works. I had tried piping the output of awk to column -t but I got an extra tab at the end of all rows with floating-point numbers which didn't appear in the integer row. Now I realise it's because I included a tab within CONVFMT. Also thanks for the reminder about cat & awk. I always forget about it. Much appreciated!
    – Arynio
    Apr 23, 2020 at 14:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .