Home > Blockchain >  Check file for string match & a secondary string match followed by altering result line only
Check file for string match & a secondary string match followed by altering result line only

Time:03-18

I've tried to double grep into a sed but the sed ignores the filtered lines.

I have a file with:

    <address domain='0x000' bus='0x71' slot='0x00' function='0x0' />
    <address domain='0x000' bus='0x71' slot='0x00' function='0x1' />
    <address domain='0x000' bus='0x71' slot='0x00' function='0x2' />
    <address type='obo' domain='0x000' bus='0x71' slot='0x0c' function='0x0' />
    <address domain='0x000' bus='0xdt' slot='0x00' function='0x0' />
    <address type='obo' domain='0x000' bus='0x71' slot='0x01' function='0x0' />
    <address domain='0x000' bus='0xdt' slot='0x00' function='0x1' />

I'd like to focus on lines with address domain, filtered into lines with function=0x0... and finally only changed the bus IDs

For example: If I'm trying to update all busses with 0xdt and function 0x0, with LABEL_1 the end result would look like...

    <address domain='0x000' bus='0x71' slot='0x00' function='0x0' />
    <address domain='0x000' bus='0x71' slot='0x00' function='0x1' />
    <address domain='0x000' bus='0x71' slot='0x00' function='0x2' />
    <address type='obo' domain='0x000' bus='0x71' slot='0x0c' function='0x0' />
    <address domain='0x000' bus='LABEL_1' slot='0x00' function='0x0' />
    <address type='obo' domain='0x000' bus='0x71' slot='0x01' function='0x0' />
    <address domain='0x000' bus='LABEL_1' slot='0x00' function='0x1' />

The problem is that it is difficult to focus on specific lines when there are so many lines with duplicate fields. I was able to grep twice into my desired filter, but cannot figure out how to alter the desired string and save to that same file.

Thank you for any guidance.

CodePudding user response:

Since it looks like a XML file, it can be properly done with xmllint and XPath

Get the count of matching nodes

xmllint --xpath 'count(//address[@function="0x0" and @bus="0xdt"])' test.xml

Change the value of first found node then iterate over the rest using count

(printf 'cd //address[@function="0x0" and @bus="0xdt"][%d]/@bus\n' 1; echo -e 'set LABEL_1\nsave\nbye') | xmllint --shell test.xml

bus > set LABEL_1
bus > save
bus > bye

Make sure to take a backup of the file.

CodePudding user response:

Suggesting one line awk script:

  awk '/address domain=/ && /bus='0xdt'/ && /function='0x0'/{sub("bus='0xdt'","bus='LABEL_1'")}1' input.txt

Output:

<address domain='0x000' bus='0x71' slot='0x00' function='0x0' />
<address domain='0x000' bus='0x71' slot='0x00' function='0x1' />
<address domain='0x000' bus='0x71' slot='0x00' function='0x2' />
<address type='obo' domain='0x000' bus='0x71' slot='0x0c' function='0x0' />
<address domain='0x000' bus='LABEL_1' slot='0x00' function='0x0' />
<address type='obo' domain='0x000' bus='0x71' slot='0x01' function='0x0' />
<address domain='0x000' bus='0xdt' slot='0x00' function='0x1' />

Notice output does not match given example!!!

awk script explanation:

/address domain=/       # for a line matching RegExp /address domain=/
&& /bus='0xdt'/         # and matching matching RegExp /bus='0xdt'/
&& /function='0x0'/ {   # and matching matching RegExp /function='0x0'/
  sub("bus='0xdt'","bus='LABEL_1'"); # substitute  RegExp /bus='0xdt'/ with "bus='LABEL_1'"
}
{print} # print each line
  • Related