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