1

My data file looks like:

10 -0.314690785295
20 -0.251967909317
30 -0.215271387106
40 -0.189228416217

The desired output is:

10 -0.0627229
20 -0.0994193
30 -0.1254623
3
  awk 'BEGIN {first_row = 0; col_val=""}{ if (first_row == 0) {first_row = $2; col_val=$1} else {print col_val " " first_row - $2; col_val=$1}}'

This is the output from the command line:

 $ echo "10 -0.314690785295
 20 -0.251967909317
 30 -0.215271387106
 40 -0.189228416217" | awk 'BEGIN {first_row = 0; col_val=""}{ if (first_row == 0) {first_row = $2; col_val=$1} else {print col_val " " first_row - $2; col_val=$1}}'
 10 -0.0627229
 20 -0.0994194
 30 -0.125462

Ok now for why this works:

The BEGIN clause defines a section of code executed as initialization before starting. In this location we initialize the two variables that we will keep track of for the rest of the logic.

In the main part of the program, in the second set of {}. we define the logic that will execute for each line in the input (You can also prepend a pattern to only run on some lines but that is outside of the scope of this answer).

The logic tests if the first_row value is set. If it is not, then this is the first line of the input, and we just need to initialize the first_row value to be the second sting in the line which is $2, we also need to copy the string that was in the first column $1 to match your desired output, we copy that value in col_val.

Else, which is every other line in the input, we print the col_value a space and the result of the subtraction of the first_row with the value at the current line in the second position $2 so first_row - $2. We then copy the new string value in the first column of the input into col_val.

I did not understand what you really needed the first time :).. This is the awk script that will do what you want.. because 10 - 20 is -10 not 10.

 awk '{ if (NR == 1) { for (i = 1; i <= NF; i++){ first_row[i] = $i} } else { for (i = 1; i <= NF; i++){ printf "%s ", first_row[i] - $i }; printf "\n"}}'

Note that the output looks like this which is slightly different from what you expected for the first column I added another column to show the progression.

 echo "10 -0.314690785295 18
 20 -0.251967909317 12
 30 -0.215271387106 35
 40 -0.189228416217 44" | awk '{ if (NR == 1) { for (i = 1; i <= NF; i++){first_row[i] = $i} } else { for (i = 1; i <= NF; i++){ printf "%s ", first_row[i] - $i }; printf "\n"}}'
 -10 -0.0627229 6 
 -20 -0.0994194 -17 
 -30 -0.125462 -26 
  • I added some explanation if you want to know how/why it works ;) glad I could help. – Rob Feb 9 '16 at 20:25
  • That's even great. Thanks for your nice explanation! – baban Feb 9 '16 at 20:28
  • Just a small query, if I have more than 2 columns and if I want to do the same then what changes need to be done? – baban Feb 9 '16 at 20:59
  • None. as long as the extra columns are after the first two. unless you need some of that information to be printed. – Rob Feb 9 '16 at 21:16
  • Sorry, my mistake. I wanted to say if I have a 3rd column and if I also do the same operation in column 3 like we did here in column 1 & 2. I mean in 3rd column also if I want to do the row operation? – baban Feb 9 '16 at 21:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.