tags:

views:

221

answers:

3

Here is what I am trying to do in a Perl script:

$data="";
sub loadXMLConfig()
{
     $filename="somexml.xml"
     $data = $xml->XMLin($filename);
}

sub GetVariable()
{
     ($FriendlyName) = @_;
     switch($FriendlyName)
     {
         case "My Friendly Name" {print $data->{my_xml_tag_name}}
         ....
         ....
         ....
      }
}

The problem is I am using Perl just because I am reading from an XML file, but I need to get these variables by a shell script. So, here is what I am using:

$ perl -e 'require "scrpt.pl"; loadConfigFile(); GetVariable("My Variable")' 

This works exactly as expected, but I need to read the XML file every time I am getting a variable. Is there a way I could "preserve" $data across shell calls? The idea is that I read the XML file only once. If no, is there is a more simple way I could do this? These are the things I can't change:

  • Config File is an XML
  • Need the variables in a shell script
+2  A: 

You can do this in two steps. You want to create a stored Perl data structure if you haven't done so already, and when you have, you the stored version so you don't have to parse it again.

There are may ways to accomplish this, but here's a version using Storable:

 use Storable qw(nstore retrieve);

 my $stored_data_structure = 'some_file_name';

 my $data = do {
      # from the stored data structure if it is there
      if( -e $stored_data_structure ) {
           retrieve( $stored_data_structure );
           }
      # otherwise parse the xml and store it
      else {
           my $data = $xml->XMLin( $xml_filename );
           nstore( $data, $stored_data_structure );
           $data;
           }
      };

You might also consider inverting your concept. Instead of a shell script that calls your Perl script, have your Perl script call your shell script:

 # load the data, as before

 # set some environment variables
 $ENV{SomeThing} = $data->{SomeThing};

 # now that the environment is set up
 # turn into the shell script
 exec '/bin/bash', 'script_name'
brian d foy
Thanks, I tested and it made the trick. However on each variable read it will be reading from the stored file. But thanks, I didn't know you could do this in perl.
Freddy
+5  A: 

When I need some information, retrieved by Perl, in a shell script, I generate shell script by Perl and set environment variables via eval:

myscript

#!/bin/bash
BINDIR=`dirname $0`
CONFIG=$BINDIR/config.xml
eval `$BINDIR/readcfg $CONFIG`
echo Running on the $planet near the $star.

readcfg

#!/usr/bin/perl
use XML::Simple;
my $xml = XMLin('config.xml', VarAttr => 'name', ContentKey => '-content');
while (my ($k, $v) = each %{$xml->{param}}) {
    $v =~ s/'/'"'"'/g;
    $v = "'$v'";
    print "export $k=$v\n";
}

config.xml

<config>
    <param name="star">Sun</param>
    <param name="planet">Earth</param>
</config>
codeholic
Really nice!. Thanks
Freddy
This reads the XML file every time, which is what I thought you didn't want to do.
brian d foy
No, you read the XML only once, after that all XML tags are just shell variables and could be used across your shell script without calling the readcfg again.
Freddy
I mean, it reads the XML every time that you run the shell script.
brian d foy
+2  A: 

You can simply store the values in shell-executable file. assuming bourne shell (sh) script and that you know beforehand a list of variable names that interest you:

$data="";
sub loadXMLConfig()
{
     $filename="somexml.xml"
     $data = $xml->XMLin($filename);
}

sub GetVariable()
{
     ($FriendlyName) = @_;
     switch($FriendlyName)
     {
         case "My Friendly Name" {
             print "$FriendlyName='$data->{my_xml_tag_name}'; export $FriendlyName\n"
         } # Use "export var=value" form for bash
         ....
         ....
         ....
      }
}

sub storeVariables {
    # @variables list defined elsewhere - this is just a sketch
    foreach my $variable (@variables) { 
        GetVariable($variable);
    }
}

And then call as follows:

$ perl -e 'require "scrpt.pl"; loadConfigFile(); storeVariables();' > my_vars.sh
$ source my_vars.sh 

And the my_vars.sh can be sourced many many times

DVK
Thanks, it definitely will work. However, a more elegant way was suggested which basically do the same thing using eval on the shell side instead of loading the file.
Freddy