in reply to how to set environment vars

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

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

    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...

        ack! join(" ", @ARGV)???? What if there are spaces or special characters? You've just added another bug and another injection attack.

        This is getting very complicated. And this my point. Compare this to the simple solution I posted, which has none of these problems.

        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