Personally, I would rather use YAML or one of the config-modules from CPAN, but it seems, other non-Perl programs are also depending on the environment, right?
This imperfect script should do some very basic parsing and interpolation. However, it would fail in situations like Y=`echo fails` or where here-documents are involved. If you
need every functionality that you shell provides, stay with it. You might be able to get rid of the wrapper script using exec or system, though.
use strict;
use warnings;
use Shell::Parser;
use Data::Dumper;
sub parse_shellscript_from_fh {
my ($fh) = @_;
my %vars;
my $parser = new Shell::Parser syntax => 'bash',
handlers => {
assign => sub {
my ($self, %args) = @_;
my ($name, $value) =
$args{token} =~ /^\s*(\w+)\s*=\s*\"(.*)\"\s*$/s;
if ( defined $value ) {
#-- multi-line/array? $value =~ s/\n//msg;
$vars{$name} = $value;
} else {
warn "No value for variable ", ($name//'?'), "\n";
}
}
};
#-- parsing
my $text = join("", <$fh>);
$parser->parse( $text );
$parser->eof;
#-- rudimentary variable interpolation
my $max_passes = 5;
my $not_substituted;
for (1 .. $max_passes ) {
$not_substituted = 0;
foreach my $varname ( keys %vars ) {
$vars{$varname} =~ s|\$(\w+)| $vars{$1} // do{ "\$$1" } |ge;
$not_substituted += $vars{$varname} =~ tr/$/$/;
}
last unless $not_substituted;
}
die "Recursion or too few parses ... " if $not_substituted;
return \%vars;
}
print "Vars: ", Dumper( parse_shellscript_from_fh( *DATA ) ), "\n";
__DATA__
A="foo"
B="some other data"
C="appending $A"
D="
some list
with more data
and $B
"
X=<<EOF
does not work there
EOF
Y=`echo fails`
Result:
No value for variable ?
No value for variable ?
Vars: $VAR1 = {
'A' => 'foo',
'D' => '
some list
with more data
and some other data
',
'C' => 'appending foo',
'B' => 'some other data'
};