http://www.perlmonks.org?node_id=507533

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

Hi All,
I have a script to set the environment variables.

This script needs to "sourced" from the perl/cgi script.

I used system command and tried it. Then tried printing a environment variable. Not sure whether the file is sourced or not.

So, How do I source a env csh file and make sure.

Thanks
rsennat

Replies are listed 'Best First'.
Re: how to set environmental vars
by ikegami (Patriarch) on Nov 10, 2005 at 20:53 UTC

    sh scripts can only "source" sh scripts.
    csh scripts can only "source" csh scripts.
    Perl scripts can only "source" Perl scripts.

    What we can do is have the run csh script and output its env variables in an easily parsable format. env can help us here. In fact, it can even be done without modifying the csh script — let's call it "script.csh" — using the following Perl code:

    my $env = `csh -c 'source script.csh; env'`; foreach my $line (split("\n", $env)) { my ($key, $val) = split('=', $line, 2); $ENV{$key} = $val; }

    Updated: I simplified my post by inlining the "wrapper script" into the executed command.

    Updated: Added the closing backtick that was accidently deleted.

      I did not get your idea on using a wrapper script... can you please explain a bit more...

        I realized my post was hard to read so I updated it. I even removed the need for a wrapper script. Does that help?
WRONG: environmental variables => RIGHT: environment variables
by merlyn (Sage) on Nov 10, 2005 at 21:42 UTC
Re: how to set environmental vars
by BUU (Prior) on Nov 10, 2005 at 21:01 UTC
    To elaborate slightly, in linux land, processes can not change their parent's environment. Children typically inherit their parent's environment but when you exit a process, any changes you've made to the environment are lost. This means that when you use "system" to execute your CSH script, any changes it makes to the environment are lost when it exits and your perl script will never see it.

    The best solution is to print your values to STDOUT or just have perl parse the CSH or some such.
Re: how to set environmental vars
by blue_cowdawg (Monsignor) on Nov 10, 2005 at 22:57 UTC
        So, How do I source a env csh file and make sure.

    Consider the following:

    #!/usr/bin/perl -w source_it() unless $ENV{foo}; printf "%s = %s\n",$_,$ENV{$_} foreach keys %ENV; exit(0); sub source_it{ exec "echo 'source env.csh ; perl $0' | csh -s"; }

    I tested it, it works.

    What I'm doing here is looking for a variable that I know should have been set by the sourced in file and if it isn't set I call the sub that execs off a "one-liner" to invoke csh, source in the environment and then re-execute the script. Once that happens the variable I'm looking for is set and I just continue to execute the script as planned. This will work with ksh, bash, sh, with differing command line switches.

    This has the additional advantage is that in the event one or more of the values is the result of a scriplet or function buried in the sourced in file it still works. Just parsing the setenv lines won't make that happen.


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

      In your solution:

      • There's a potential for an infinite loop.
      • You're running one shell and one shell command more than you need.
      • You're vulnerable to two injection attacks. (Only one fixed)
      • You're not passing parent Perl's arguments to the child Perl. (Not fixed)
      • You're not passing parent Perl's switches to the child Perl. (Not fixed)

      Fix:

      #!/usr/bin/perl -w if (!defined($ENV{foo})) { if (@ARGV > 0 && $ARGV[0] eq 'nested') { die("Unable to find value for env var FOO\n"); } exec 'csh', '-c', "source env.csh ; perl $0 nested"; die("Unable to execute csh: $!\n"); } printf "%s = %s\n",$_,$ENV{$_} foreach keys %ENV;

        While we're at fixing each other's code:

        | | exec '/bin/csh', '-c', "source env.csh ; perl $0 nested"; | |
        You forgot about the issue of an executable being in $PATH and being executed instead of the shell we are after.

        As far as an infinite loop is concerned I did state that I am testing for a variable that I know exists and is set in the env.csh file.

        Fixing the last two bullet items you are referring to is not covered in fix either AFAICT. Any arguments being passed to the script are going to be lost. To fix that I'd add

        exec '/bin/csh', '-c', sprintf("source env.csh ; perl $0 nested %s" +,join(" ",@ARGV));

        And believe it or not there are still some ways to break this...

Re: how to set environmental vars
by coreolyn (Parson) on Nov 10, 2005 at 20:54 UTC

    Read your vars in from your file and populate the enviornment vie the %ENV hash

    $ENV{'SHELLVAR') = $value

Re: how to set environmental vars
by polettix (Vicar) on Nov 10, 2005 at 20:55 UTC
    You could start showing us what you tried exactly, i.e. the contents of the csh file and of the relevant piece of your Perl/CGI script that tries to "source" it.

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.
Re: how to set environment vars
by rsennat (Beadle) on Nov 11, 2005 at 10:03 UTC
    Hi blue_cowdawg,
    I get an error with the code, sorry if I miss anything silly.
    #!/usr/bin/perl -w if (!defined($ENV{foo})) { if (@ARGV > 0 && $ARGV[0] eq 'nested') { die("Unable to find value for env var FOO\n"); } exec '/bin/csh', '-c', sprintf("source script1.csh ; perl $0 nested %s +",join(" ",@ARGV)); die("Unable to execute csh: $!\n"); } printf "%s = %s\n",$_,$ENV{$_} foreach keys %ENV;
    The script1.csh
    setenv PATH_ORIG "${PATH}" setenv MANPATH_ORIG "${MANPATH}" setenv LD_LIBRARY_PATH_ORIG "${LD_LIBRARY_PATH}"

    And the Error I get is
    Missing $ on loop variable at tmp.pl line 13.

    Please help me out...
    Thanks