4

I have a data file named File-1. I have to match a pattern DATA_POINTS, and then after skipping one line I want to print 6th column of the following lines.

  • File-1 example:
    here ! some other data exist but all of them are totally different from the below data!
    
    In simple words following data is completely unique.
    
    
    DATA_POINTS
    12
       0.0000000000     0.0000000000     0.0000000000  20   !  A
       0.5000000000     0.5000000000     0.0000000000  20   !  B
       0.7500000000     0.5000000000     0.2500000000  20   !  C
       0.7500000000     0.3750000000     0.3750000000  20   !  D
       0.0000000000     0.0000000000     0.0000000000  20   !  E
       0.5000000000     0.5000000000     0.5000000000  20   !  F
       0.6250000000     0.6250000000     0.2500000000  20   !  U
       0.7500000000     0.5000000000     0.2500000000  20   !  W
       0.5000000000     0.5000000000     0.5000000000  20   !  L
       0.7500000000     0.3750000000     0.3750000000  20   !  K
       0.6250000000     0.6250000000     0.2500000000  20   !  U
       0.5000000000     0.5000000000     0.0000000000  20   !  X
    
  • Desired output
    S1 = A
    S2 = B
    S3 = C
    S4 = D
    S5 = E
    S6 = F
    S7 = U
    S8 = W
    S9 = L
    S10= K
    S11= U
    S12= X
    

The pattern DATA_POINTS does not repeat in the file, and an exact match is desired.

Nearest Solution

I got this command from another qsn. this is working if the 6th column in a same row of pattern

awk '/DATA_POINTS/{i==0 ; i++; getline; print "S"i"=", $6}' File-1
0

4 Answers 4

4

The following awk program should do the job:

awk 'BEGIN{n=-1}
     n>0{printf "S%-*d=%s\n",w,++i,$6; if (i==n) {i=0;n=-1}}
     n==0{n=$1;w=length($1)}
     $0=="DATA_POINTS"{n=0}' file

This will:

  • At the beginning, initialize a "status flag" n with -1, meaning "outside the data block".
  • When a line consisting only of the string DATA_POINTS is encountered, set n to 0, meaning "the next line contains the number of data points"
  • When n is zero, the content of the line is interpreted as number of data points and stored in n. The length of that number (in characters/digits) is stored in a field w used for formatting the output later.
  • When n is larger than 0, indicating we are inside the "data" block, print the "key" with the counting variable i (formatted for fixed width using w and left-adjusted as in your output example) and the 6th field of the line, until i is equal to n, at which point n is reset to -1

This has probably more functionality than you need to, in that it can handle data blocks which are not located at the end of the file (it respects the number of data lines specified in the header, rather than reading just until end-of-file).

Note that the method for finding DATA_POINTS is currently full string matching, which is the most robust method if the actual string can contain special characters. If you want partial string matching, or regular expression matching, use either

index($0,"DATA_POINTS") { ... }

or (as in your example)

/DATA_POINTS/ { ... }

In addition, if you want to guard against misinterpreting empty lines, replace n>0 and n==0 with n>0&&NF and n==0&&NF, respectively.

0
2
$ awk '/DATA_POINTS/{c=3} c&&!--c{f=1} f{printf "S%d = %s\n", ++s, $6}' file
S1 = A
S2 = B
S3 = C
S4 = D
S5 = E
S6 = F
S7 = U
S8 = W
S9 = L
S10 = K
S11 = U
S12 = X

To start printing from the 27th line from the matching line (inclusive) instead of the 3rd, just change 3 to 27.

See https://stackoverflow.com/questions/17908555/printing-with-sed-or-awk-a-line-following-a-matching-pattern/17914105#17914105 for more information on the above approach and more ways to do something after a match.

1
  • 1
    Thank you!!! @Ed Morton. I really appreciate your one line answer. :)
    – sai
    Jan 13, 2021 at 17:40
2

Make use of the range operator ,. Start is the data points line and end is eof.

awk '
 /DATA_POINTS/,0 {
    if ( /DATA_POINTS/ ) {
      getline; next 
   }
   printf "S%-2d=%s%s\n", ++k, OFS, $6
 }
' file
2
  • 2
    It's very rarely best to use a range expression as it makes trivial programs very slightly briefer than using a flag but then causes you to have duplicate conditions (as in this case) or a complete rewrite if the problem gets the tiniest bit more complicated. See also awk.freeshell.org/AllAboutGetline for when/how to use getline.
    – Ed Morton
    Jan 13, 2021 at 14:19
  • thank you @guest_7.
    – sai
    Jan 13, 2021 at 17:44
0

This is a one-line solution extracting the line number with sed, adding 2 with bc, using tail to extract the data block and finally awk to get the correct column. Probably not the cleanest or easiest solution, but for me it was clearer than using only awk.

sed -n '/DATA_POINTS/=' $file | xargs -i echo '{}+2' | bc | xargs -i tail -n+{} $file | awk '{print $6}'

You must log in to answer this question.

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