1

I have the large xml file with the following type of lines:

<test type="one" valid="yes" description="something">
                    twilight-.*\.iso\.auth</test>

<test type="one" valid="no" description="something else">
                    testlite-.*\.cop</test>

<test type="two" valid="yes" description="something else">
                    messing-.*\.cop\.auth</test>
<test type="three" valid="yes" description="something else">messing-.*\.cop\.auth</test>

There are many such lines in my xml file. My requirement is that:

  1. If we match the pattern 'valid="yes"' in the first line and '.auth' in the second line, then duplicate both the lines. And in the second line, replace ".auth" with ".newauth"
  2. If we match BOTH the patterns 'valid="yes" and '.auth' in the same line, then duplicate only that line and replace ".auth" with ".newauth"

Here is how the output should look like:

<test type="one" valid="yes" description="something">
                    twilight-.*\.iso\.auth</test>
<test type="one" valid="yes" description="something">
                    twilight-.*\.iso\.newauth</test>

<test type="one" valid="no" description="something else">
                    testlite-.*\.cop</test>

<test type="two" valid="yes" description="something else">
                    messing-.*\.cop\.auth</test>
<test type="two" valid="yes" description="something else">
                    messing-.*\.cop\.newauth</test>
<test type="three" valid="yes" description="something else">messing-.*\.cop\.auth</test>
<test type="three" valid="yes" description="something else">messing-.*\.cop\.newauth</test>

Note that, there are many such lines(pairs of lines) in my xml file that needs to be replaced. But the rule to replace it remains the same as above. Also, note that for the fourth line, the entire xml tag is part of a single line. So, the awk expression becomes a little more complicated in this case.

Thanks in Advance!

0

Updated to meet revised question

Try this. Seems to work fine with GNU awk 4.2.1 here.

awk '/valid="yes"/{print;if(!/<\/test>/){a=$0;getline;print $0"\n"a}gsub(/\.auth/,".newauth")}1' filename
  • 1
    Thanks a lot Steve. This works perfectly fine for the above text. Are conditional statements possible within awk? The reason I ask is few of the lines in my .xml file have the entire tag in the same line. Eg: <filter type="two" valid="yes" description="something else">messing-.*\.cop\.newauth</test>. So, in those cases the above awk script is making a copy of the next line too which isn't required. – John Bosco Aug 12 at 5:07
  • 2
    @JohnBosco match the pattern 'valid="yes"', then duplicate that line as well as the second line was what you asked about. If you have data that is requiring something else, that should be part of the question too, not a follow-up question in a comment. – Kusalananda Aug 12 at 5:33
  • 1
    Sure. Added it there. – John Bosco Aug 12 at 5:50
  • 1
    Thanks Steve for you answers – John Bosco Aug 13 at 15:12
0

Using sed editor we can do it very easily as shown:

$ sed -e '
    /valid="yes"/!b
    h;/\.auth/G
    /\n/P;//s/.*\n//
    s/\.auth/.newauth/;t
    $q;N;/\.auth/!{P;D;}
    p;s//.newauth/
' test.xml
  • Thank you Rakesh – John Bosco Aug 13 at 15:12
0

I was able to achieve what I want(Based on @Steve's solution), in a two step process:

  1. Solve #1:
    awk '/valid="yes"/{print;a=$0; next} /.auth/{print $0"\n"a;gsub(/\.auth/,".newauth")}1' test.xml > newtest.xml
  1. Using the xml file from the above step, solve #2:
    awk '/valid="yes"/ && /.auth/{print $0;gsub(/\.auth/,".newauth")}1' newtest.xml > final.xml

Is it possible to combine these two operations into one awk operation?

0

If you really know what you are doing and that your XML can't be formatted differently or contain any traps, you don't need two steps or complicated scripts. This one does it simply in one pass:

sed -e '/valid="yes"/!b' -e '/\.auth/!N;p;s/\.auth/.newauth/'
  • /valid="yes"/!b jumps (b) to the end of the script for lines not (!) contaning the pattern, so everything else is left as it was
  • /\.auth/!N is for lines not (!) containing .auth: for those lines, we append the Next line
  • print the current pattern space (may be one or two lines). Anyhow, we duplicate as required
  • s/\.auth/.newauth/ does the required replacement. The unmodified line/lines was already printed, now we modify it for the duplicate and it will be printed at the normal end of processing.
  • Step 5? There is no step 5.
  • Thanks Philippos – John Bosco Aug 13 at 15:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.