Luka
Luka

Reputation: 125

AWK to search a specific sequence and if found search in the next line another sequence version2

I'm trying to find a string in a txt format and each time it's found then look for an specific string to change for another string and avoiding reading the first sequence of the line.

Imagine the nexts hexadecimal txt:

0000  09 06 07 04 00 00 01 00 1d 03 78 2c a1 2a 02 01   
0010  b7 09 01 47 30 22 a0 0a 4b 08 33 04 03 92 22 14   
0020  17 f0 a1 0b 80 00 81 00 84 01 00 86 00 85 00 83   
0030  07 91 94 71 06 00 07 19

0000  09 06 07 04 00 00 01 00 2b 03 4b 27 a1 25 02 01   
0010  00 09 01 66 30 4b a0 0a 80 08 33 04 03 92 22 14   
0020  17 f0 a1 06 82 00 84 00 85 00 82 07 91 94 71 06   
0030  00 07 19

Expected output:

0000  09 06 07 04 00 00 01 00 1d 03 78 2c a1 2a 02 01   
0010  b7 09 01 47 30 22 a0 0a 4b 08 33 04 03 92 22 25   
0020  17 f0 a1 0b 80 00 81 00 84 01 00 86 00 85 00 83   
0030  07 91 94 71 06 00 07 19

0000  09 06 07 04 00 00 01 00 2b 03 4b 27 a1 25 02 01   
0010  00 09 01 66 30 4b a0 0a 80 08 33 04 03 92 22 25   
0020  17 f0 a1 06 82 00 84 00 85 00 82 07 91 94 71 06   
0030  00 07 19

I need that each time I encounter a 4b sequence to look for 14 sequence and if found look in the next line the first string, which is in this case 17 and if this string is 17 change 14 to 25. What you have on the left is a sequence which gives you the line of the txt you are, so that it's not interesting to analysis because it's repeated in each paragraph

What I have is the next:

gawk  ' { for ( i = 1; i <= NF; ++i ) {

    if ( $i == "4b" )
        r = 1
    if ( r && ($i == "14" ))
        t = 1

  }
}
1 ' example.txt example2.txt

I don't know well how to jump to start reading the next line

Summary:

The idea is to search for 4b and if it's encountered then start looking for 14 in the same line and it must be in the last position of the line. And if in the second field of the next line appears 17 then changed 14 to 25

What I have is this:

gawk -i inplace  ' { for ( i = 1; i <= NF; ++i ) {

    if ($i == "4b" )
        r = 1
    if (r && $i == "14" )
        z = 1
       $i = x
    if ( z && r && $i == "17")
        z = 0
        r = 0
        x = "25"


  }
}
1 ' example.txt example2.txt

The main problem is that I don't know how to verify if 14 is the second field of the next line

Upvotes: 3

Views: 117

Answers (2)

anubhava
anubhava

Reputation: 785276

Using gnu-awk, you may try this:

awk -v RS= '{ORS=RT} {$0 = gensub(/(\s4b\s(.+\s)?)14([[:blank:]]*\n\S+[[:blank:]]+17\s)/, "\\125\\3", 1)} 1' file

0000  09 06 07 04 00 00 01 00 1d 03 4b 2c a1 2a 02 01
0010  b7 09 01 47 30 22 a0 0a 80 08 33 04 03 92 22 25
0020  17 f0 a1 0b 80 00 81 00 84 01 00 86 00 85 00 83
0030  07 91 94 71 06 00 07 19

0000  09 06 07 04 00 00 01 00 2b 03 4b 27 a1 25 02 01
0010  00 09 01 66 30 1d a0 0a 80 08 33 04 03 92 22 25
0020  17 f0 a1 06 82 00 84 00 85 00 82 07 91 94 71 06
0030  00 07 19

RegEx Demo

Upvotes: 3

RavinderSingh13
RavinderSingh13

Reputation: 133538

With your shown samples only, could you please try following. Written and tested with GNU awk.

awk '
!NF{ found1=found2=prevLine=prevRestLine=0 }
/(^|[[:space:]])4b([[:space:]]|$)/{
  found1=1
  print
  next
}
found1 && /(^|[[:space:]])14([[:space:]]|$)/{
  found2=1
  prevLine=$0
  match($0,/[[:space:]]+$/)
  s=substr($0,RSTART,RLENGTH)
  sub(/[0-9]+[[:space:]]+$/,"")
  prevRestLine=$0
  next
}
found1 && found2{
  if($2==17 && prevLine && prevRestLine){
    print prevRestLine 25 s ORS $0
    prevLine=prevRestLine=0
  }
  if($2!=17 && prevLine){
    print prevLine ORS $0
    prevLine=0
  }
  found1=found2=0
  next
}
1
' Input_file

Explanation: Adding detailed explanation for above.

awk '                                            ##Starting awk program from here.
!NF{ found1=found2=prevLine=prevRestLine=0 }     ##If line is null then reset.
/(^|[[:space:]])4b([[:space:]]|$)/{              ##if 4b is present(with spaces or without) then:
  found1=1                                       ##Set found1
  print                                          ##print current line.
  next                                           ##Leave all other statements from here.
}
found1 && /(^|[[:space:]])14([[:space:]]|$)/{    ##Checking if found1 is set AND 14 is found(with or without space)
  found2=1                                       ##Set found2 here.
  prevLine=$0                                    ##Set prevLine value to current line.
  match($0,/[[:space:]]+$/)                      ##Get ending spaces of line.
  s=substr($0,RSTART,RLENGTH)                    ##create s with above matched values.
  sub(/[0-9]+[[:space:]]+$/,"")                  ##Substitute digits spaces at last with NULL in current line.
  prevRestLine=$0                                ##Set prevRestLine value to current line.
  next                                           ##Leave all other statements from here.
}
found1 && found2{                                ##Checking if found1 and found2 are set.
  if($2==17 && prevLine && prevRestLine){        ##Checking if 2nd field is 17 and prevLine, prevRestLine are set.
    print prevRestLine 25 s ORS $0               ##Printing prevRestLine 25 s ORS $0 here.
    prevLine=prevRestLine=0                      ##unset here.
  }
  if($2!=17 && prevLine){                        ##If 2nd column is not 17 AND prevLine is set.
    print prevLine ORS $0                        ##Printing prevLine ORS and current line.
    prevLine=0                                   ##unset prevLine here.
  }
  found1=found2=0                                ##unset found1 and found2 here.
  next                                           ##Leave all other statements from here.
}
1                                                ##1 will print current line.
' Input_file                                     ##Mentioning Input_file name here.

Upvotes: 1

Related Questions