2

could anyone help me with following problem:
I have a tab delimited file that doesn’t have the same number of columns in every row. I need to divide the value in first column subsequently by the values in all other columns. As a result I would like to get the final number to a new file.

example_file.txt

0.0002  0.2    0.2    0.6   
0.03    0.3    0.7     
0.004   0.1    0.2    0.005   0.3  0.005  

I filled all empty rows with 1, to avoid problem with division by 0:

awk '{for(i=NF+1;i<=6;i++)$i="1"}1' < example_file.txt > example_file_filled.txt

example_file_filled.txt

0.002   0.2   0.2      0.6    1   1    
0.03    0.3   0.7        1    1   1    
0.004   0.1   0.2    0.005    0.3 0.005    

Expected output:

output.txt

0.083  
0.14  
26666.66  

I know that I can:
- either divide the first column by second column, then take this value and divide by third column etc.
- or multiply all columns from second column till the last one and use this value to divide the first column

For the first possibility I was trying to use:

awk '{$1=$1/$2; $2=""; print $0 }' example_file_filled.txt 

This divides the first row by the second one and prints as output the result followed by the numbers that were not yet used for division. I tried to loop over it to get it done until there is no second row, but I didn’t manage.

Could anyone suggest a solution? My real file has >100 of columns. I am mostly using bash / unix, but I will be happy to learn also from other approaches.
Thanks in advance!

user_pb
  • 35
  • 5

2 Answers2

1

Use a loop to go through the other columns, then divide:

awk '{ val = 1; for (i = 2; i <= NF; ++i) val *= $i; print $1 / val }' file

Or just do successive divisions, again with a loop:

awk '{ for (i = 2; i <= NF; ++i) $1 /= $i; print $1 }' file

It's up to you how you want to treat the presence of a 0 in any column - you can add an if before performing the division if you like.

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
0

With perl

$ cat ip.txt 
0.002  0.2    0.2    0.6   
0.03    0.3    0.7     
0.004   0.1    0.2    0.005   0.3  0.005  

$ perl -lane '$a=$F[0]; $a /= $_ foreach (@F[1..$#F]); print $a' ip.txt 
0.0833333333333333
0.142857142857143
26666.6666666667

Limiting decimal points:

$ perl -lane '$a=$F[0]; $a /= $_ foreach (@F[1..$#F]); printf "%.3f\n", $a' ip.txt 
0.083
0.143
26666.667


See Perl flags -pe, -pi, -p, -w, -d, -i, -t? for explanation on perl command line options

Sundeep
  • 23,246
  • 2
  • 28
  • 103