I've got a 'config' file that a shell script sources - I can't change the config file format but need to use the data in perl. Currently, I have a shell script that exports the values and then runs the perl script and just use $ENV{val} from within perl. But this seems clunky. Is there a way of parsing something like this in perl:

A="foo" B="some other data" C="appending $A" D=" some list with more data and $B "

Which with my current implementation, I'd have a shell script:

#!/bin/bash - . foo.conf export A export B export C export D ./foo.pl

And then:

#!/usr/bin/perl my %exp_vars = ( A => 'SCALAR', B => 'SCALAR', C => 'SCALAR', D => 'ARRAY', ); my $env; foreach my $var (keys %exp_vars) { my $type = $exp_vars{$var}; my $val = lc $var; if (! defined $ENV{$var} or length($ENV{$var}) <= 1) { push @out, "# [$var] not exported"; next; } if ($type eq 'ARRAY') { @{$env->{$val}} = ($ENV{$var} =~ m/(?:\s+)?(\S+)/g); } elsif ($type eq 'SCALAR') { $env->{$val} = $ENV{$var}; } }

So, how do I remove the shell script from this?

EDIT

After looking at the messing with Shell::Parser and looking at the suggestions, I took what I needed and came got the below (basically, I didn't see that Shell::Parser was givin me anything, so I parsed out the variables myself and then look any shell values that need to be interpreted:

#!/bin/env perl use strict; use warnings; use Data::Dumper; sub parse_sh { my ($data) = @_; my $r; $data =~ s/((?: *#.*?)?\n+)/\n/gs; # Remove comment lines $data =~ s/(\n+)/\n/gs; # Remove blank lines $data =~ s/ *(\S+)=("?)(.*?)\2 *\n/$r->{lc($1)}="$3"/gse; return $r; } sub parse_sh_maint { my ($r, $noset) = @_; # Interpolate variable names my $max_passes = 5; my $not_substituted; for (1 .. $max_passes ) { for my $k (keys %$r) { next unless (ref(\$r->{$k}) eq 'SCALAR'); $r->{$k} =~ s|\$(\w+)| $r->{lc($1)} // do{ "\$$1" } |ge; $not_substituted += $r->{$k} =~ tr/$/$/; } last unless $not_substituted; } # Remove remaining variables and make variables with spaces and newl +ines arrays for my $k (keys %$r) { $r->{$k} =~ s/\$\S+ *?//gs; # Remove remaining varia +bles $r->{$k} =~ s/\s+/\n/gs; # Remove leading spaces if (not grep { $_ eq $k } @$noset) { my %dedupe = map { $_ => 1 } split(/ |\n/, $r->{$k}); $r->{$k} = (); @{$r->{$k}} = keys %dedupe; } } return $r; } open(my $fh, "<", $ARGV[0]); my $content = do { local $/ = <$fh> }; my $stuff = parse_sh_maint(parse_sh($content), [qw/scalar1 scalar2/]); print "Vars: " . Dumper($stuff), "\n";

In reply to Parsing bash data by ag4ve

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.