Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Perl Script to append xml file

Posted on 2013-11-27
32
Medium Priority
?
210 Views
Last Modified: 2015-04-23
I have an xml file like below.

 <interface type='network'>
      <mac address='52:54:00:a3:24:30'/>
      <source network='phybrid'/>
      <target dev='vnet3'/>
      <alias name='net1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </interface>

I want a perl script which adds below lines to this

<filterref filter='clean-traffic'>
        <parameter name='IP' value='1.2.3.1'/>
        <parameter name='IP' value='3.2.3.3'/>
      </filterref>

So the final output should be like below

<interface type='network'>
      <mac address='52:54:00:fc:70:00'/>
      <source network='phybrid'/>
      <target dev='vnet3'/>
      <filterref filter='clean-traffic'>
        <parameter name='IP' value='1.2.3.1'/>
        <parameter name='IP' value='3.2.3.3'/>
      </filterref>
      <alias name='net1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
0
Comment
Question by:pehalwaan
  • 15
  • 11
  • 5
32 Comments
 
LVL 27

Assisted Solution

by:wilcoxon
wilcoxon earned 1332 total points
ID: 39681638
The simplest (possibly naive version) would be:
$xml =~ s{(<target dev=.*?/>)$}{$1\n    <filterref filter='clean-traffic'>\n        <parameter name='IP' value='1.2.3.1'/>\n        <parameter name='IP' value='3.2.3.3'/>\n    </filterref>}msg;

Open in new window

0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39681665
This is not working. Can you please give me a script which accepts xml file as an argument

I would really appreciate it
0
 
LVL 27

Expert Comment

by:wilcoxon
ID: 39681763
What's not working?  Here's an alternate way to do it as a one-liner command...
perl -pe -i.bak 's{(<target dev=.*?/>)$}{$1\n    <filterref filter=\'clean-traffic\'>\n        <parameter name=\'IP\' value=\'1.2.3.1\'/>\n        <parameter name=\'IP\' value=\'3.2.3.3\'/>\n    </filterref>}' <filename>

Open in new window


One side questions - why does your XML use single quotes around attribute values?  Both are valid but double quotes is the norm in XML.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 3

Author Comment

by:pehalwaan
ID: 39681787
KVM
This is what i get while running. These are KVM xml files. These are auto-generated when we create kvm's.

I am unable to work with one liners. Can you provide a detailed script.
0
 
LVL 85

Expert Comment

by:ozo
ID: 39681802
perl -i.bak -pe "s#(\s*)(?=<alias name)#\$1<filterref filter='clean-traffic'>\n\$1 <parameter name='IP' value='1.2.3.1'/>\n\$1 <parameter name='IP' value='3.2.3.3'/>\n\$1</filterref>#" file.xml
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39681824
There are many other occurrences of aliasname which are getting replaced too in the file.

What i am trying out is parsing the xml file and appending my new lines in interface tag.

Please suggest if you have some better approach
0
 
LVL 85

Expert Comment

by:ozo
ID: 39681844
perl -i.bak -pe "s#(\s*)(?=<alias name='net1'/>)#\$1<filterref filter='clean-traffic'>\n\$1 <parameter name='IP' value='1.2.3.1'/>\n\$1 <parameter name='IP' value='3.2.3.3'/>\n\$1</filterref>#" file.xml
0
 
LVL 27

Expert Comment

by:wilcoxon
ID: 39681861
Sigh.  I forgot the -i has to go before the -e.  Try this one-liner.  If there are other instances of "alias name" and "target dev", you will very likely have to do as you suggest (and actually parse the XML).
perl -i.bak -pe "s{(<target dev=.*?/>)$}{$1\n    <filterref filter='clean-traffic'>\n        <parameter name='IP' value='1.2.3.1'/>\n        <parameter name='IP' value='3.2.3.3'/>\n    </filterref>}" test1.xml

Open in new window

0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39681874
These one liners are wonderful and work perfectly. But can you help me with the script because IP values coming in this will be not fixed , they will be coming as arguments in my production environment
0
 
LVL 85

Expert Comment

by:ozo
ID: 39681880
perl  -MO=Deparse -i.bak -pe "s#(\s*)(?=<alias name='net1'/>)#\$1<filterref filter='clean-traffic'>\n\$1 <parameter name='IP' value='1.2.3.1'/>\n\$1 <parameter name='IP' value='3.2.3.3'/>\n\$1</filterref>#"

BEGIN { $^I = ".bak"; }
LINE: while (defined($_ = <ARGV>)) {
    s[(\s*)(?=<alias name='net1'/>)][$1<filterref filter='clean-traffic'>\n$1 <parameter name='IP' value='1.2.3.1'/>\n$1 <parameter name='IP' value='3.2.3.3'/>\n$1</filterref>];
}
continue {
    die "-p destination: $!\n" unless print $_;
}
0
 
LVL 27

Assisted Solution

by:wilcoxon
wilcoxon earned 1332 total points
ID: 39681940
For a script version, try this...
use strict;
use warnings;
use Tie::File; # not strictly necessary but I like it when editing files
my $fil = shift or die "Usage: $0 file ip1 ... ipX\n";
tie my @lines, 'Tie::File', $fil or die "could not open $fil: $!";
# may need to restructure next line
# can't remember if @lines gets recalced each iteration or not
for my $i (0..@lines-1) {
    if ($lines[$i] =~ m{^(\s+)<target dev=.*?/>\s*$}) {
        my $spc = $1;
        splice @lines, $i+1, 0, "$spc<filterref filter='clean-traffic'>", map({ "$spc    <parameter name='IP' value='$_'/> } @ARGV), "$spc</filterref>";
    }
}
untie @lines;

Open in new window

0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39683489
When using this one liner inside my perl script it gives below error

String found where operator expected at /usr/local/sbin/KVM3.pm line 414, near "n"    /etc/libvirt/qemu/$cust_id-$server_id.xml""
syntax error at /usr/local/sbin/KVM3.pm line 414, near ""perl -i.bak -pe "s#(\s*)(?=<source network='pyhbrid'/>)#\$1<filterref filter='clean-traffic'>\n\$1 <parameter name='IP' value='$wan_primary_ip'/>\n\$1</filterref>#"

Can you help write a simple formatted code for this. This is very urgent
0
 
LVL 85

Expert Comment

by:ozo
ID: 39683555
this is how a one liner can be converted into a script
perl -MO=Deparse  -Mwarnings -Mstrict -i.bak -pe "s#(\s*)(?=<source network='pyhbrid'/>)#\$1<filterref filter='clean-traffic'>\n\$1 <parameter name='IP' value='$wan_primary_ip'/>\n\$1</filterref>#"
BEGIN { $^I = ".bak"; }
use warnings;
use strict;
LINE: while (defined($_ = <ARGV>)) {
    s[(\s*)(?=<source network='pyhbrid'/>)][$1<filterref filter='clean-traffic'>\n$1 <parameter name='IP' value=''/>\n$1</filterref>];
}
continue {
    die "-p destination: $!\n" unless print $_;
}
-e syntax OK
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39684256
I have written a script to change root password directly in shadow file. Below it is

my $admin_password=shift;
my $password_salt=qx{perl -e 'print crypt("$admin_password","\$6\$saltsalt\$") . "\n"'};
print "$password_salt";
qx{perl -pe 's|(root):(\$.*?:)|\1:\$6\$SALTsalt\$$password_salt:|' shadow > shadow.new};

When i run these perl commands from command line, they work fine, but when i write them in a pl file and run pl file, i get below errors.

perl p.pl dfr
Final $ should be \$ or $name at -e line 1, within string
syntax error at -e line 1, near ","$6$saltsalt$""
Execution of -e aborted due to compilation errors.

I am unable to stat what is wrong here. Can anybody help
0
 
LVL 85

Expert Comment

by:ozo
ID: 39684265
Did you mean
my $password_salt=qx{perl -e 'print crypt("$admin_password","\$6\$saltsalt\\\$") . "\n"'};        
Or easier
my $password_salt=crypt($admin_password,"$6$saltsalt\$")."\n";
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39684279
easier method is working but not replacing new salt in shadow file
0
 
LVL 85

Expert Comment

by:ozo
ID: 39684291
Neither $6 nor $SALTsalt seems to be defined in
qx{perl -pe 's|(root):(\$.*?:)|\1:\$6\$SALTsalt\$$password_salt:|' shadow > shadow.new};
and it doesn't replace anything in shadow file, it would replace in shadow.new file
and are you sure that qr|(root):($.*?:)| matches in shadow file?
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39684293
below is pattern in shadow.new file

root:$6$izkFWw9QZFNE7Y6B$5LgqIJPO1LT9WTq/DgThqzuYNq8QmOwpkVnC0aWdU727kdljidRXe1WVT2wlqn1RS6MLCOMEjTSbVzC5YTBYa1:16007:0:99999:7:::

And i didn't get your point of $6 and $SALT
0
 
LVL 85

Expert Comment

by:ozo
ID: 39684301
Did you want
{local @ARGV=("shadow");
local $^I=".old";
s/(?:^root:)[^:]/$saltsalt$password_salt/ and print while <>;
}
0
 
LVL 85

Expert Comment

by:ozo
ID: 39684304
Since $6 and $SALTsalt are in "" quotes, the -e script will try to interpolate it.
Did you mean to say \\\$6$saltsalt
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39684315
No. My just motive is to change root password by replacing "hashed password " in shadow file. As i mentioned, if i run these one liners from command line, they work completely fine.

Can you help me get the correct script
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39684358
Any suggestions/answers
0
 
LVL 85

Expert Comment

by:ozo
ID: 39685052
I made a couple of suggestions.  If you find them unsuitable, I am unsure what kinds of improvements you would require.
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39686168
Please help me fix this

SCRIPT

#!/usr/bin/perl

my $admin_password=shift;
my $password_salt=qx{openssl passwd -1 $admin_password};    ##### Generate
print "$password_salt";
$old_password_salt=qx{cat shadow.new | grep root | cut -d: -f2};
print "$old_password_salt";
qx{sed -i -e 's|$old_password_salt|$password_salt|g' shadow.new};

OUTPUT

perl p.pl bghuin
$1$tOuKv7mH$HKHlphoXl4LTSRUXWqWvM.
$6$izkFWw9QZFNE7Y6B$5LgqIJPO1LT9WTq/DgThqzuYNq8QmOwpkVnC0aWdU727kdljidRXe1WVT2wlqn1RS6MLCOMEjTSbVzC5YTBYa1
sed: -e expression #1, char 108: unterminated `s' command

PLEASE HELP.
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39686184
PLEASE REPLY
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 39686214
Please HELP
0
 
LVL 85

Expert Comment

by:ozo
ID: 39686305
chomp $password_salt;
chomp $old_password_salt;
0
 
LVL 85

Accepted Solution

by:
ozo earned 668 total points
ID: 39686400
Or

#!/usr/bin/perl
my $admin_password=shift;
my $password_salt=qx{openssl passwd -1 $admin_password};    ##### Generate
print $password_salt;
chomp  $password_salt;
@ARGV=("shadow.new");
$^I="";
while( <> ){
    s/:([^:]*):/:$password_salt:/ && print STDERR "$1\n" if /root/;
    print;
}
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 40740472
I've requested that this question be deleted for the following reason:

Solved it
0
 
LVL 27

Expert Comment

by:wilcoxon
ID: 40740473
ozo and I both provided significant help on this question.  The person asking often would just reply with things like "help" without any details about what was not working.  The asker never responded with what was not working in either my final script or ozo's final script.  As such, it seems like at least the majority of the points should be distributed.
0
 
LVL 3

Author Comment

by:pehalwaan
ID: 40740647
@All-

I am sorry for the action. One of my team members deleted it. I am accepting the solution.
0

Featured Post

Vote for the Most Valuable Expert

It’s time to recognize experts that go above and beyond with helpful solutions and engagement on site. Choose from the top experts in the Hall of Fame or on the right rail of your favorite topic page. Look for the blue “Nominate” button on their profile to vote.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I have been pestered over the years to produce and distribute regular data extracts, and often the request have explicitly requested the data be emailed as an Excel attachement; specifically Excel, as it appears: CSV files confuse (no Red or Green h…
Background Still having to process all these year-end "csv" files received from all these sources (including Government entities), sometimes we have the need to examine the contents due to data error, etc... As a "Unix" shop, our only readily …
Six Sigma Control Plans
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

971 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question