Solved

Perl Script to append xml file

Posted on 2013-11-27
32
184 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 26

Assisted Solution

by:wilcoxon
wilcoxon earned 333 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 26

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
 
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 84

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 84

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 26

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 84

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 26

Assisted Solution

by:wilcoxon
wilcoxon earned 333 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 84

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 84

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
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 3

Author Comment

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

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 84

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 84

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 84

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 84

Expert Comment

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

Accepted Solution

by:
ozo earned 167 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 26

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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

In the distant past (last year) I hacked together a little toy that would allow a couple of Manager types to query, preview, and extract data from a number of MongoDB instances, to their tool of choice: Excel (http://dilbert.com/strips/comic/2007-08…
How to remove superseded packages in windows w60 or w61 installation media (.wim) or online system to prevent unnecessary space. w60 means Windows Vista or Windows Server 2008. w61 means Windows 7 or Windows Server 2008 R2. There are various …
Learn several ways to interact with files and get file information from the bash shell. ls lists the contents of a directory: Using the -a flag displays hidden files: Using the -l flag formats the output in a long list: The file command gives us mor…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

744 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now