Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

setting perl ENV from file

by kcorcam (Initiate)
on Sep 16, 2003 at 16:06 UTC ( [id://291862] : perlquestion . print w/replies, xml ) Need Help??

kcorcam has asked for the wisdom of the Perl Monks concerning the following question:

I know how to basically read a file of name/value pairs and set up the environment for a perl script. However if part of the 'value' contains a variable how do I resolve it so that I can correctly use it in my program? For example, if my config file contains the fllowing 2 name/value pairs, how do I get 'mydir' to resolve to '/kelly/test.log'. FILE: myfile=test.log mydir=/kelly/$myfile thanks guys

Replies are listed 'Best First'.
Re: setting perl ENV from file
by Abigail-II (Bishop) on Sep 16, 2003 at 16:10 UTC
    Is your file one that can be sourced in the shell? Then use the following code near the top of your program (assuming you use something like Bourne shell, Bash, Korn shell, POSIX shell, ...).
    my $ENVIRONMENT = "/some/file/with/environment/variables/"; if (@ARGV && $ARGV [0] eq '--sourced_environment') { shift; } else { if (-f $ENVIRONMENT) { # # Now we perform a double exec. The first exec gives us a +shell, # allowing us the source the file with the environment var +iables. # Then, from within the shell we re-exec ourself - but wit +h an # argument that will prevent us from going into infinite r +ecursion. # # We cannot do a 'system "source $ENVIRONMENT"', because # environment variables are not propagated to the parent. # # Note the required trickery to do the appropriate shell q +uoting # when passing @ARGV back to ourselves. # # Also note that the program shouldn't normally be called +with # '--sourced_environment' - if so, pick something else. # @ARGV = map {s/'/'"'"'/g; "'$_'"} @ARGV; exec << " --"; source '$ENVIRONMENT' exec $0 --sourced_environment @ARGV; -- die "This should never happen."; } }


Re: setting perl ENV from file
by coreolyn (Parson) on Sep 16, 2003 at 17:19 UTC

    I'm sure this isn't the cleanest but this is the function I've been using reliably for several years now without a problem against VAR=$VALUE files. In effect I load the vars that will require interpolation into the enviornment, then parse the config file, then add the new values to the environment.

    The first function function (readDat) just gets the info from another file. The second code snippet (unpackDatArray) does the actual value setting ( including $VARS as long as they are in the environment. ) The third snippet (getEnvValue) substitutes the $VAR for it's value.

    There are a few functions in these snippets like 'debug' that you'll have to comment out or add similar functionality for them ( i.e. setEnv ).

    # Reads a text file with var=values pairs line delimited # Storing the values into a hash filled array. sub readDat { # Grab the passed parameter my $filename = $_[0]; my $state = $_[1]; # Establish the array to hold the aquired Data # and pass back to calling Function my @Data; # The ubiquitous $i counter my $i = 0; debug( "Reading dat file - $filename\n", 5 ); # Register a filehandle local (*DATFILE); # Open the file for read open (DATFILE, $filename) or debug( "Can't open $filename: $1", 10 +0); # Read through the file one line at a time FORA:while (<DATFILE>) { debug("Proccessing Line = \n$_\n", 0); # Skip over any comments if ( /#.*/ ) { next FORA; } # Clean up any extraneous garbage chomp; # no newline s/^\s+//; # no leading white s/\s+$//; # no trailing white # If clean up eliminated any data worth reading # lets skip to the next line next unless length; debug( "Loading Line = \n$_\n", 0 ); # We can't load the lines with $VARS as we will # loose any values so we'll make sure to escape them # (the $'s that is) s/\$/\\\$/g; # localizing $var and $value to make sure # they are clean out on every read. my ($var, $value) = split(/=/,$_); if ( $var && $value ) { debug( "\$var = $var \$value = $value\n", 0 ); } # Stuff those puppies into a hash and store # the hash into our @Data array # (See Camel 3rd ed pgs 278 - 279) $Data[$i]{$var} = $value; # Increment and get the next $i++; } # Send the info back to the caller return @Data; }


    # Used to unpack data read from .dat files (excluding modify.dat) sub unpackDatArray { my @dat = @_; # Unpack the data # (See Camel 3rd ed pgs 278 - 279) my ( $i, $var, $value); for $i ( 0 .. $#dat ) { for $var ( keys %{ $dat[$i] } ) { $value = $dat[$i]{$var}; if ( $var && $value ) { debug("\$var = $var \$value = $value\n", 0); # set our workspace $_ = $value; # If the values have a $ in them we must get # the environmental Var value and substitue it # into our value. /(\\\$)(\w+)(.*)/ ; if ( $2 ) { $value = getEnvValue($value); } # Set the Environment $_ = $value; # eliminate surrounding quoutes from string s/^\"//g; s/$\"//g; $value = "$_"; my %newHashValue; $newHashValue{$var} = $value; setEnv(%newHashValue); } } } }


    # This is a nasty little sub that parses out what Environmental # Var to retrieve and then inserts it into the string sub getEnvValue { my $envValue = ""; # set the workspace $_ = $_[0]; # As long as a question mark exists keep working # on it (Bad place for a possible 'hang' or looping # problem.) while ( /\$/ ) { # Seperate out the VarName and the remaining string /(\\\$)(\w+)(.*)/ ; # eliminate surrounding quoutes from string # get that freakin delimeter my $delimeter = $`; my $envVarString = $2; my $workString = $3; debug( "\$delimeter = $delimeter\n \$envVarString = $envVarString\n \$workString = $workString\n", 0 ); # Get the environments value and substitute it into the # current line if it exists if ( $ENV{$envVarString} ) { $envValue = $delimeter . $ENV{$envVarString} . $workString +; s/$envVarString/$ENV{$envVarString}/g; } else { $envValue = $delimeter . "NA" . $workString; s/$envVarString/NA/g } debug( "Harvest::FileFuc::getEnvValue\n \$Workpace = $_\n \$workString = $workString\n So far returning $envValue\n",1); # If theres no more $'s in the string pop it back on # the return value $_ = $envValue; } # Return the work return $envValue; }
Re: setting perl ENV from file
by herveus (Prior) on Sep 16, 2003 at 17:56 UTC

    I faced a similar question in a Korn shell environment. After trying to be tricky and parse the stinker, I realized that the simple approach was superior:

    sub profile { my $self = shift; my $profile = shift; foreach (`. $profile; env`) { chomp; next unless /=/; my ($var, $value) = split(/=/, $_); $ENV{$var} = $value; } }

    Pass the path to the source file to the sub and it populates %ENV... I use backtick substitution to get the shell to evaluate the profile and dump its environment in a reliable format. C shell would require some modifications to the details, but the basic structure still stands.


      my ($var, $value) = split(/=/, $_);

      Better make that

      my ($var, $value) = split(/=/, $_, 2);

      or else it will break if a value contains a =.


Re: setting perl ENV from file
by kcorcam (Initiate) on Sep 16, 2003 at 16:19 UTC
    Is there anyway to do it from reading and parsing the file?
      Assuming you have gotten $key and $value from the file, you could:
      $value =~ s((\$\{(\w+)\}|\$(\w+))) ($ENV{$2} or $ENV{$3} or $1)eg;
      This would support an input file with two possible interpolations:
      key1=value key2=value$key1 key3=${key1}value
      It depends on the order of definition. You could iterate the replacement step across all strings until the keys stop changing, but that may raise new problems.

      [ e d @ h a l l e y . c c ]

      This works for simple cases but is not very robust.
      use Data::Dumper; my %envron; while (<DATA>) { chomp; my ($key, $value) = /(.+)=(.*)/; next unless defined $key; $value =~ s/\$(\w+)/$environ{$1}/g; $environ{$key} = $value; } print Data::Dumper->Dump([\%environ], ["*environ"]); __DATA__ myfile=test.log mydir=/kelly/$myfile longdir=/$myfile$mydir __OUTPUT__ %environ = ( 'longdir' => '/test.log/kelly/test.log', 'mydir' => '/kelly/test.log', 'myfile' => 'test.log' );



Re: setting perl ENV from file
by pelagic (Priest) on Jun 08, 2004 at 10:56 UTC
    I know, it's almost a year ago, but I just stumbled over it today because I had a similar request:
    `exec ksh -c ". set_env"`;