sed search and replace after xml tag

Hi All,
I'm new to sed .

In following XML file

   <interface type='direct'>
      <mac address='52:54:00:86:ce:f6'/>
      <source dev='eno1' mode='bridge'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <interface type='direct'>
      <mac address='52:54:00:ab:d5:77'/>
      <source dev='eno2' mode='bridge'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </interface>

i have add one new xml tag after <source dev='eno1' mode='bridge'/> , which is <target dev='New1'/> .

for i in `eno1 eno2 eno3 eno4`
do
        echo "Updating macvtap device names for $i"
	sed -i.bak "/source dev='$i'/a <target dev='New$cnt'/>" 
$XML_FILE
    	cnt=`expr $cnt + 1`
done

The above is not working. Please let me know how to do it?

Do you have in mind that eno# is not the only form of Ethernet device names? eno# is only the naming for onboard network cards.

It can be too be a name like ens1 or ens3f0 ore a few other combinations. See

PredictableNetworkInterfaceNames

Yes, i'm aware of that.

All i wanted is give a persistent name to the macvtap devices using this script.

I have taken care of finding the interface names, now only thing have to do is in that xml, <source dev='eno1' mode='bridge/>, append the next line with specific target dev names, using this sed command.

You want to cycle the for loop through each given word

for i in eno1 eno2 eno3 eno4
do

Optimization: your shell certainly does not need an external call of expr for integer arithmetics

 cnt=$((cnt+=1))

to clarify, the following is command substition(call a command and get the output of it).

`eno1 eno2 eno3 eno4`

As you just want the bare words, omit the apostrophe.

And for the nit-picker in me, this works to too:

((cnt++))
1 Like

Do you want to use a counter (which, BTW, you did not initialize and thus is the empty string for the first loop) or the source device's number?

for i in eno1 eno2 eno3 eno4
    do    echo "Updating macvtap device names for $i"
          sed "/source dev='$i'/a <target dev='New${i#${i%?}}'/>"  XML_file
    done
1 Like
${i#${i%?}}

Interesting construct :slight_smile: Another way of expressing...

${i: -1}

...and i just got confused with ...

${i:-1}

which does not work as desired because :- is default value assignment.

Hi stomp,
You are correct in noting that some shells (including recent versions of bash and ksh93 ) can use ((cnt++)) as a shortcut for cnt=$((cnt+1)) and MadeInGermany's suggestion of cnt=$((cnt+=1)) and can also use last=${var: -1} as a shortcut for RudiC's suggestion of last=${var#${var%?}} to get the last character from the expansion of $var , but more shells (in fact any POSIX-conforming shells) support arithmetic expansions ( $((expression)) ), and the ${var#pattern} and ${var%pattern} parameter expansions. The arithmetic command ( ((expression)) ) and the substring parameter expansions ( ${var:offset} and ${var:offset:length} ) are extensions allowed, but not defined by the standards, and are not provided by as many shells.

But, I don't know of any shell where cnt=$((cnt++)) is required to be the same as cnt=$((cnt+1)) because the order in which a post-increment operation on a variable and an assignment to the same variable happens is unspecified. In both ksh (version: (AT&T Research) 93u+ 2012-08-01) and bash (version: 3.2.57(1)-release (x86_64-apple-darwin15)), the commands:

cnt=1
cnt=$((cnt++))
echo $cnt

produce the output:

1

Imagine the sequence of operations of cnt=$((cnt++)) as:

  1. save the value of cnt (1),
  2. increment the value of cnt to 2
  3. return the saved value (1) as the result of the arithmetic expansion, and
  4. finally, assign the returned value to cnt (negating the post-increment).

But, it could also be processed as:

  1. save the value of cnt (1),
  2. return the saved value (1) as the result of the arithmetic expansion,
  3. assign the returned value to cnt , and
  4. finally, increment the value of cnt to 2.

You have exactly the same problem in C and C++ with:

#include <stdio.h>
int main() {
	int	i = 1;
	int	j;

	for(j = 1; j <= 5; j++)
		printf("%d\n", i = i++);
}

Building it on some systems gives the warning:

cc     x.c   -o x
x.c:7:23: warning: multiple unsequenced modifications to 'i' [-Wunsequenced]
                printf("%d\n", i = i++);
                                 ~  ^
1 warning generated.

and, when run, producing the output:

1
1
1
1
1

or:

1
2
3
4
5

(But, on the system I'm currently using, it always produces just 1s as the output.)

1 Like

Sorrry, I wanted to suggest

cnt=$((cnt+1))

Added the = without seeing the double assignment.
BTW, only the other assignment, should be possible as well

: $((cnt+=1))