albertkao9
albertkao9

Reputation: 504

Match multiple patterns in xml file, copy and change the matched lines with awk, sed

I want to match multiple patterns in xml files, copy and modify the matched lines. The xml format is in a multi-line pattern,

<security-role-assignment>
...
</security-role-assignment>

which are on separate lines (not on the same line). I want to duplicate the block that contains the string "beanA_users" within the multi-line pattern, then replace the duplicated block with:

s#beanA_users#beanB_users#
s#runas_a#runas_b#

My environment have awk, sed, grep, but not xml_grep nor xmlstarlet.

awk -V
GNU Awk 5.0.0, API: 2.0 (GNU MPFR 4.1.0, GNU MP 6.2.1).

in.xml

<security-role-assignment>
    <role-name>beanA_users</role-name>
    <principal-name>runas_a</principal-name>
</security-role-assignment>

out.xml

<security-role-assignment>
    <role-name>beanA_users</role-name>
    <principal-name>runas_a</principal-name>
</security-role-assignment>
<security-role-assignment>
    <role-name>beanB_users</role-name>
    <principal-name>runas_b</principal-name>
</security-role-assignment>

in2.xml

<security-role-assignment>
    <role-name>beanXYZ_users</role-name>
    <principal-name>runas_test</principal-name>
</security-role-assignment>
<security-role-assignment>
    <role-name>beanA_users</role-name>
    <principal-name>runas_a</principal-name>
</security-role-assignment>
<security-role-assignment>
    <role-name>beanC_users</role-name>
    <principal-name>runas_c</principal-name>
</security-role-assignment>

out2.xml

<security-role-assignment>
    <role-name>beanXYZ_users</role-name>
    <principal-name>runas_test</principal-name>
</security-role-assignment>
<security-role-assignment>
    <role-name>beanA_users</role-name>
    <principal-name>runas_a</principal-name>
</security-role-assignment>
<security-role-assignment>
    <role-name>beanB_users</role-name>
    <principal-name>runas_b</principal-name>
</security-role-assignment>
<security-role-assignment>
    <role-name>beanC_users</role-name>
    <principal-name>runas_c</principal-name>
</security-role-assignment>

e.g.

awk -f test.awk in.xml > out.xml
awk -f test.awk in2.xml > out2.xml

test.awk (this is my best version so far, still need a lot of work)

/<security-role-assignment>/ {
   xmlbuf = xmlbuf $0 ORS
   gsub(/beanA_users/,"beanB_users",xmlbuf)
   gsub(/runas_a/,"runas_b",xmlbuf)
   print; next
}
xmlbuf!="" {
   printf "%s", xmlbuf
   xmlbuf=""
}
{ print }

Upvotes: 1

Views: 115

Answers (2)

sseLtaH
sseLtaH

Reputation: 11207

Using sed

$ sed -z 's/.*/&&/;s/\(bean\)[[:alpha:]]/\1B/2;s/\(runas_\)[[:alpha:]]/\1b/2' input_file
<security-role-assignment>
    <role-name>beanA_users</role-name>
    <principal-name>runas_a</principal-name>
</security-role-assignment>
<security-role-assignment>
    <role-name>beanB_users</role-name>
    <principal-name>runas_b</principal-name>
</security-role-assignment>

Upvotes: 2

ufopilot
ufopilot

Reputation: 3975

# if your strings are static
# beanA_users#beanB_users
# runas_a#runas_b    
# Try this
$ awk 'NR!=FNR{gsub(/beanA_users/,"beanB_users"); gsub(/runas_a/,"runas_b")}1' in.xml in.xml

<security-role-assignment>
    <role-name>beanA_users</role-name>
    <principal-name>runas_a</principal-name>
</security-role-assignment>
<security-role-assignment>
    <role-name>beanB_users</role-name>
    <principal-name>runas_b</principal-name>
</security-role-assignment>

Upvotes: 2

Related Questions