Luka
Luka

Reputation: 125

Sed command to find string and replace another string (txt format)

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

Upvotes: 1

Views: 343

Answers (5)

potong
potong

Reputation: 58351

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.

Upvotes: 0

Raman Sailopal
Raman Sailopal

Reputation: 12867

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.

Upvotes: 0

Thor
Thor

Reputation: 47089

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

Upvotes: 1

Shigufta Yasmin
Shigufta Yasmin

Reputation: 1

If this can help,

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

Upvotes: 0

Jay
Jay

Reputation: 76

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

Upvotes: 2

Related Questions