-3

I have a text file saved in the name 'test_file' that contain 6 rows and 7 columns as given below

 0.00 5.8 2.0  5.0 6.0 8.0 0.0
  10.00 5.8 2.0  1.0 1.0 1.2 9.6
  10.00 9.3 2.2  2.0 1.4 2.5 9.6
  30.00 9.3 2.2  1.2 1.5 1.9 1.4
  30.00 9.3 2.2  3.2 2.4 1.2 4.1
  60.00 9.8 3.5  1.4 2.7 3.2 4.5

I want to do some text manipulation in second and third column.

In the third column first two rows values should be same (2.0 and 2.0) and next three rows values are just the 0.2 increment of second row value(2.0+0.2=2.2,2.0+0.2=2.2,2.0+0.2=2.2).However, i don't want to change last row i want to keep it as it is.

After that in the second column, first two rows values should be just the multiplication of, first two rows of third column with 2.9. similarly next three rows of second column are just the multiplication of next three rows of third column with 4.227

other columns values i don't want to change at all.

Now i want to change the first two rows value of third column sequentially, 2.1,2.2....2.5 followed by same increment and multiplication.

For example when i change first two rows values of third column from original 2.0 to 2.1 then the expected output should be

0.00 6.09 2.1  5.0 6.0 8.0 0.0
  10.00 6.09 2.1  1.0 1.0 1.2 9.6
  10.00 9.722 2.3  2.0 1.4 2.5 9.6
  30.00 9.722 2.3  1.2 1.5 1.9 1.4
  30.00 9.722 2.3  3.2 2.4 1.2 4.1
  60.00 9.8 3.5  1.4 2.7 3.2 4.5

and i want to save the output file in different name such as file2.1.txt....file2.5.txt

2 Answers2

2

awk to the rescue!

$ awk 'p {print p} 
         {pp=$0; v=$3; $3+=0.1; $2*=$3/v; p=$0} 
     END {print pp}' file | column -t

0.00   6.09     2.1  5.0  6.0  8.0  0.0
10.00  6.09     2.1  1.0  1.0  1.2  9.6
10.00  9.72273  2.3  2.0  1.4  2.5  9.6
30.00  9.72273  2.3  1.2  1.5  1.9  1.4
30.00  9.72273  2.3  3.2  2.4  1.2  4.1
60.00  9.8      3.5  1.4  2.7  3.2  4.5

since you want special treatment for the last record, delay processing using the previous record p, also you want unmodified last record, so store the original previous record in pp and print at the END. Delayed printing will print the modified records and last one will be unmodified.

You can specify number formatting as well but I didn't think it was important...

To run for multiple increments, just add an outer loop

 $ for inc in {1..5}; 
   do awk -v inc=$inc '...
                       ... $3+=(inc/10) ...
                       ...' file > file."$inc".txt

   done

You can pass the increment (actually 10 times the increment) to awk script as a variable, use in in the script as well as in the output filename. The only change in the awk script is the increment.

karakfa
  • 66,216
  • 7
  • 41
  • 56
  • @lijun, please read the code and try your different increments. It shouldn't be hard since there is only one line dealing with computations. You can redirect the output to a file adding `> output.file.name`. – karakfa Oct 12 '20 at 15:03
  • you can't nest `awk` scripts like that, see my update. Outer loop is a bash loop running `awk` multiple times. There is another way to do it in one `awk` script as well. – karakfa Oct 12 '20 at 15:20
  • 1
    **The only change in the awk script is the increment.** `...` are just placeholders you need to copy from the original script. Sorry, but this is too much handholding. If you're serious in programming you need to work little harder. – karakfa Oct 12 '20 at 15:26
  • i need different value to be multiplied instead of 2.9 i need 2.1 and instead of 4.227 i need 4.0 –  Oct 12 '20 at 16:44
1

Here's another version if you can't work with the other answer:

awk -vval=2.1 '{              # set "val" to the new value for column 3 on first two lines
  if(NR==1 || NR==2) {        # if it's the first or second line
    $3=val;                   # set column 3 to val
    $2=$3*2.9                 # set column 2 to column 3 multiplied with 2.9
  } else if(NR>=3 && NR<=5) { # else if it's line 3-5
    $3=val+0.2;               # set column 3 to val+0.2
    $2=$3*4.227               # set column 2 to column 3 multiplied with 4.227
  } else $3=$3;               # just for formatting
  print                       # print the result
}' test_file

Remove the comments (#) before you run it.

Output:

0.00 6.09 2.1 5.0 6.0 8.0 0.0
10.00 6.09 2.1 1.0 1.0 1.2 9.6
10.00 9.7221 2.3 2.0 1.4 2.5 9.6
30.00 9.7221 2.3 1.2 1.5 1.9 1.4
30.00 9.7221 2.3 3.2 2.4 1.2 4.1
60.00 9.8 3.5 1.4 2.7 3.2 4.5

To loop over a range and save it in different files you can do like below. I also made the other parameters available so you can set them when running the script:

#!/bin/bash

for val in $(seq 2.1 0.1 2.5)
do
  awk -vval=$val -vfmul=2.9 -vadd=0.2 -vsmul=4.227 '{
    if(NR==1 || NR==2) {
      $3=val;
      $2=$3*fmul
    } else if(NR>=3 && NR<=5) {
      $3=val+add;
      $2=$3*smul
    } else $3=$3;
    print
  }' test_file > output$val
done
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • great u r really an expert....Thanks for ur support...here i am accepting ur answer...is quite easy and concise to understand –  Oct 12 '20 at 19:18