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

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

Hi all,

I need to source a shell script file that sets various environment variables. The shell script file isn't simply a set of "export VAR=VALUE" where I can simply parse the file. The script file may be in C-Shell, Korn shell, BASH or a myriad of obscure shells depending on which environment it is running in and which user.

source some_env_file.sh . some_env_file.sh

I'm unable to use a wrapper script that sources the file and then calls the Perl script for political reasons. If you're writing a part in *shell, why do you need Perl?

So, infamous and all powerful monks of the Perl multiverse, how do I source a shell script from within a Perl script?

Jason L. Froebe

Blog, Tech Blog

Replies are listed 'Best First'.
Re: How to "source" a shell file in Perl?
by SuicideJunkie (Vicar) on Jun 12, 2013 at 19:17 UTC
    If you're writing a part in *shell, why do you need Perl?

    "Same reason why you walk all the way from the parking lot to your desk, but still need a car, Boss."

      Funny but not technically or politically helpful. ;-)

      Jason L. Froebe

      Blog, Tech Blog

      just because when sharing work ar legacy some may not have used same language just because you may use a perl script to setup an shell env to launch a tool command etc .. have you ever done some work ?
Re: How to "source" a shell file in Perl?
by LanX (Saint) on Jun 12, 2013 at 19:28 UTC

    > I'm unable to use a wrapper script that sources the file and then calls the Perl script ...

    well that's the only sane solution, buddy.

    > The shell script file isn't simply a set of "export VAR=VALUE" where I can simply parse the file...

    Too bad, you can't export variables to a parent process.

    The only (insane) solution which come to my mind is to call a shell script which sources your stuff and dumps it somewhere where the parent Perl can restore it from, e.g a file or piped to STDOUT.

    That's such an insane approach that I don't even wanna elaborate more on it.

    Maybe try to find some ksh, csh or sh ready to use snippets, able to export JSON.

    > for political reasons.

    Send them here and I'll tell them they are idiots.

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      Pushing the environment variables to the parent process isn't possible I know but what I could do is create a child process, capture the environment variables that are set and send that back to the parent process to handle. A bit of a hack but that should satisfy the requirements.

      Jason L. Froebe

      Blog, Tech Blog

        Congratulations, works for me :)

        open my $source,'-|',"bash /tmp/wrapper.sh" or die "$!"; my $dump= do { local $/; <$source>}; my $VAR1; eval $dump; print $VAR1->{MONK}; #> jfroebe

        lanx@nc10-ubuntu:/tmp$ cat wrapper.sh . /tmp/src.sh perl -MData::Dumper -e' print Dumper \%ENV' lanx@nc10-ubuntu:/tmp$ cat src.sh export MONK=jfroebe lanx@nc10-ubuntu:/tmp$

        Thats an extremely stable approach, I can't think of a way to make it break! =)

        you could even try to generate the code from wrapper.sh dynamically on the fly, hence avoiding any security/dependencies issues.

        Cheers Rolf

        ( addicted to the Perl Programming Language)

        UPDATE

        > you could even try to generate the code from wrapper.sh dynamically on the fly

        works! =)

        my $bashcode=<<'_bash_'; . /tmp/src.sh; perl -MData::Dumper -e "print Dumper \%ENV"; _bash_ open my $source, '-|', qq{bash -c '$bashcode'} or die "$!"; my $dump= do { local $/; <$source>}; my $VAR1; eval $dump; print $VAR1->{MONK}; #> jfroebe

        UPDATE

        far less code, same result

        my $bashcode=<<'__bash__'; . /tmp/src.sh; perl -MData::Dumper -e 'print Dumper \%ENV'; __bash__ my $VAR1; eval qx{bash -c "$bashcode"}; print $VAR1->{MONK}; #> jfroebe
        That was my idea.

        Actually you could call a wrapper-shell-script which sources and calls a second perl-script.

        The perl-script use Data::Dumper to serialize %ENV and prints the string to STDOUT.

        opening the shell script with "wrapper.sh |" should¹ be sufficent to grab the dump.

        the second perl-script might look overhead but it's cleaner and you don't need to worry about k/ba/c-sh compatibilities and about JSON.

        Cheers Rolf

        ( addicted to the Perl Programming Language)

        ¹) open

        and if the filename ends with a '|', the filename is interpreted as a comma +nd which pipes output to us.
        ...
        For three or more arguments if MODE is '|-', the filena +me is interpreted as a command to which output is to be piped +, and if MODE is '-|', the filename is interpreted as a command +which pipes output to us.
Re: How to "source" a shell file in Perl?
by Happy-the-monk (Canon) on Jun 12, 2013 at 20:53 UTC

    I see this is solved.
    Still I'd like to point you to this ancient thread of a similar nature that has recently proven of great value to me once again: Get default login environment

    Cheers, Sören

    (hooked on the Perl Programming language)

Re: How to "source" a shell file in Perl?
by Preceptor (Deacon) on Jun 12, 2013 at 19:53 UTC
    I've had to do something similar.

    You can probably do:

    my $env_from_script = `. filename; env`; my $specific_var = `. filename; echo $var_I_want`;
    It's not very nice, but - I assume you've a similar situation to me - a complicated set of shell scripts, that's got all sorts of built ins configured via a 'sourceable' file. And that file is maintained, but your version won't be.

Re: How to "source" a shell file in Perl?
by Laurent_R (Canon) on Jun 12, 2013 at 21:02 UTC

    A not very pretty but relatively simple solution I used at least once in a similar situation, not pretty but it worked:

    - my first Perl script did a number of preliminary things (reading and generating files, etc.) and then launched a shell script and then simply died;

    - the shell script did the sourcing and some other needed dirty work, and then launched another Perl script which could now work with all the environment properly set up (it could actually have launched the same Perl script with different arguments, but that looked too far-fetched).

    I have a reasonable experience of shell scripting, but I am really not an expert on the subject, nor on the fine details of the Unix execution environment. There might have been better ways to get the desired results, but once it worked, I did not feel like trying to fix or break it. I have actually also done something relatively similar under VMS, but that would probably get off-topic.

    I did not fully understand some of the discussions in the previuous posts, I hope that I am not just proposing a solution already suggested by someone else.

Re: How to "source" a shell file in Perl?
by Anonymous Monk on Jun 12, 2013 at 19:31 UTC

    A quick search seems to show that doing what you want directly may not be possible: Re: Changing parent process environment variable

    If that node (from 2007) is still correct, my first instinct would be that you do in fact need to wrap the shell script that you want to get the environment from...

Re: How to "source" a shell file in Perl?
by Anonymous Monk on Jun 12, 2013 at 23:35 UTC