1

I'm triying 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.

Imagine the next hexa txt:

02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 09 01 27 30 22 a0 0a 80 08 33 04 03 92 22 14
00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 09 01 27 30 22 a0 0a 80 08 33 04 03 92 22 14

I need that each time I encounter a 2a sequence to look for 09 01 sequence and replace with 03 02.

Expected output:

02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14

Im triying something this:

sed -i 's/09 01\(.*2a\)/03 02/g' packet.txt
0

5 Answers 5

2

I would do this with awk:

$ awk ' { for ( i = 1; i <= NF; ++i ) {
            if ( $i == "2a" )
                r = 1
            if ( r && $i == "09" && $(i+1) == "01" ) {
                r = 0
                $i = "03"
                $++i = "02"
            }
        }
      }
      1 ' hexa.txt > hexa.txt.modified

Grep the differences:

$ sdiff hexa.txt hexa.txt.modified
02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1                 02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01                 09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 09 01 27 30 22 a0 0a 80 08 33 04 03 92 22 14               | b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1                 00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01                 09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 09 01 27 30 22 a0 0a 80 08 33 04 03 92 22 14               | b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
Sign up to request clarification or add additional context in comments.

4 Comments

Thats absolutely great! Thanks a lot! By the way, could you explain the code a little bit?
The code works no matter if the replace-to-string is following the look-for-string on the same line or on the lines after. Instead of working line by line it works field by field. The 1 at the end prints the lines. The r variable steers if an upcoming "09 01" sequence shall be replaced or not. If replaced, r is set to false. Hence allowing next strings with "09 01" to stay unchanged (because not preceded by a "2a" detection). As soon as "2a" is detected, r is set to true and hence an upcoming replace-to-string will be replaced
And what does it means the 1 character in the last line?
The 1 means true to awk, filter is true, no regex, simply true and hence prints the lines out. See this: awk 1 /etc/hosts
1

Assuming you mean: "only replace if it occurs after 2a", then you can do it by transforming the bytes, so that only one 2a occurs on each line, e.g.:

<hexa.txt tr '\n' ' ' | sed 's/2a/\n&/g'

Now all you need to do is only replace 09 01 when the line starts with 2a, e.g.:

sed -E 's/(^2a.*) 09 01/\1 03 02/'

Now go back to the original formatting, i.e. 16 bytes per line:

tr '\n' ' ' | xargs -n16

All together:

<hexa.txt tr '\n' ' ' | sed 's/2a/\n&/g' |
sed -E 's/(^2a.*) 09 01/\1 03 02/'       |
tr '\n' ' ' | xargs -n16

Output:

02 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14
00 11 86 05 01 01 01 a0 11 60 0f 80 02 07 80 a1
09 06 07 04 00 00 01 00 1d 03 8a 02 01 2a 02 01
b7 03 02 27 30 22 a0 0a 80 08 33 04 03 92 22 14

Comments

0

If this can help,

cat *.txt | sed '/2a/s/09 01/02 03/g'

Comments

0

Alternative awk solution using GNU awk:

awk 'BEGIN { RS="2a" } { ORS=RS }  $0 ~ /09 01/ { $0=gensub("09 01","03 02","g",$0)}1' file

Set 2a as the record separator. Check each record for "09 01". If it exists, replace "09 01" with "03 02" with the gensub function and set this as $0. Use short hand 1 to print the record after setting the output record separator the same as the record separator.

Comments

0

This might work for you (GNU sed):

sed -zE 's/^/\x00/                       # introduce a unique delimiter
         :a;/\x00$/{s///;b}              # remove delimiter at end-of-file
         /\x002a/!{s/\x00(.)/\1\x00/;ba} # if not 2a pass over next char
         s//2a\x00/                      # next char is 2a prep for next string
         :b;/\x00$/ba                    # is it end of file
         /\x0009(\s)01/{s//03\102\x00/;ba}   # replace string and prep for 2a again
         s/\x00(.)/\1\x00/;bb' file      # not desired string so pass over char

Since the desired string (in this case09 01) may occur on another line or within in the same line twice or more, line processing is not feasible. Processing must be at character level and in this solution the entire file is processed as one string (see -z option).

Two cases are identified:

  1. The key (in this case 2a), processing within the place holder :a.
  2. The string to be replaced (09 01 with 03 02), processing within the place holder :b.

Once the key is identified, processing passes to the next case. Once the desired string has been replaced, processing is passed back the first case. Either case can terminate processing when the end-of-file is encountered.

N.B. The solution relies on the file not containing the null character hex 00.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.