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

From what I understand, you can run a shell script via perl, but any environment variables the shell script is setting will not persist once the perl script terminates? Thats what I gathered from the forums, but I am not quite sure what that means. Here is my issue, I want a perl script to execute a shell script. That shell script is setting an environment variable, then execing a binary executable. The perl script does not need to know what env variables are being set, only that the shell script ran. So am I understanding this right, that this cannot be done? A perl script cannot run a shell script that relies on env's being set by the shell? Something about parent/child processes?

Replies are listed 'Best First'.
Re: shell script via perl (clarification)
by reasonablekeith (Deacon) on Dec 07, 2005 at 10:48 UTC
    You can run a command in perl using (for example) backticks or the system function.

    Both of these will invoke a new shell, which will run in a new child process under the process currently running your perl script. The child will inherit any enviroment variables set by your perl script, but any enviroment varaibles set by the child will be lost when the child ends.

    you can check the return code of the command in perl using $?.

    system("./some_command_that_might_set_ENVs.sh"); if ($? == -1) { print "failed to execute: $!\n"; }
    ---
    my name's not Keith, and I'm not reasonable.
      "The perl script does not need to know what env variables are being set, only that the shell script ran."

      If you need to know that it ran then don't go for backticks... but reasonablekeith has correctly offered here the answer to the bit you said you needed - the exit code of the script - which you can control with the exit command.

      #!/bin/sh # # shell_script.sh # MY_VAR="something" ./simulated_binary_executable.pl echo "Returned $?" echo "Exporting MY_VAR" export MY_VAR ./simulated_binary_executable.pl echo "Returned $?" exit 0
      and (to simulate the binary you are calling from the shell script) try.pl like this
      #!/usr/bin/perl # # simulated_binary_executable.pl # use strict; use warnings; if ( $ENV{MY_VAR} ) { print "MY_VAR is '$ENV{MY_VAR}'\n"; exit 0; } else { print "MY_VAR is not set\n"; exit 1; }
      Wrapping this in a dummy of your outer perl script:
      #!/usr/bin/perl # # Dummy of outer perl script that is calling shell script # use strict; use warnings; # You could use $? later instead of defining $return my $return = system("./shell_script.sh"); if ($return == -1) { print "failed to execute: $!\n"; } elsif ($return & 127) { printf "child died with signal %d, %s coredump\n", ($return & 127), ($return & 128) ? 'with' : 'without'; } else { printf "child exited with value %d\n", $return >> 8; }
      Or rather doing away with the intermediate shell script and setting the variables it would have set from within perl:
      #!/usr/bin/perl # # Dummy of outer perl script # This time calling the binary without shell wrapper script # use strict; use warnings; # # Export the environment variable for the child binary # directly from Perl # $ENV{MY_VAR} = "something else"; my $binary = "./simulated_binary_executable.pl"; system($binary); # Run the external program if ($? == -1) { print "Child '$binary' failed to execute: $!\n"; } elsif ($? & 127) { printf "Child '%s' died with signal %d, %s coredump\n", $binary, ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($? == 0) { print "Child '%s' exited successfully.\n"; } else { printf "Child '%s' exited with value %d\n", $binary, $? >> 8; }
      Is there any possible way, where i can use environment variable set by child shell script in parent PERL script?

        Short version: no, but do read the FAQ.

Re: shell script via perl (clarification)
by Happy-the-monk (Canon) on Dec 07, 2005 at 10:46 UTC

    In Perl, you access environement variables by their names as hash keys in %ENV, so you can easily manipulate them like so:

    $ENV{PATH} = $ENV{PATH} . ":/home/toronto75/bin";

    When you execute a shell script, it inherits the environment.
    So would any other executable, so there's actually no need to call a shell script as a wrapper for that other executable.

    Update: However, when that programme terminates, and in turn, the shell script terminates after having first modified the environment and than run that other programme, the environment does not remain modified as by the shell script.

    To your Perl programme, nothing has changed, except what it did itself.

    Cheers, Sören

Re: shell script via perl (clarification)
by Perl Mouse (Chaplain) on Dec 07, 2005 at 11:12 UTC
    What you want to do works (as you should know, you did try it before asking, didn't you?)

    What the statement means is that if a Perl program (and this is not limited to Perl, it's an OS thing that applies to all processes) executes a shell (or some other program) using system, and said shell or program sets or modifies an environment variable, this new value is only visible from that shell or program, and any other programs it calls. It's not noticeble from the Perl program that called the shell.

    In fact, it's not unlike local.

    Perl --((8:>*
      Thanks everyone for your replies. Oh yes, I've tried it. In fact, I hate to admit that I have been trying to get it to work for 6 straight hours now. I think I may have a different problem with a parameter that the final binary requires. Anyway it took me a while to finaly come here and ask. I try to figure things out on my own as I am trying to rely on google and the perl docs. Buut.. I must be slow because I have read and re-read the docs on it and didnt quite get it. But I think I have a better understanding now thanks to everyone here. : )
Re: shell script via perl (clarification)
by g0n (Priest) on Dec 07, 2005 at 11:14 UTC
    From your description the process seems to be:

    Perl script X runs shell script Y
    Shell script Y sets environment variable
    Shell script Y executes binary executable Z
    binary executable Z terminates, control returns to shell script Y
    shell script Y terminates (losing environment variable setting), control returns to perl script X

    In which case the binary executable Z and shell script Y should be able to see the environment variable.

    In other words, a perl script can run a shell script that relies on setting/getting environment variables. The perl script will not be able to read the environment variables, because once the shell script terminates, the variables will be lost.

    --------------------------------------------------------------

    "If there is such a phenomenon as absolute evil, it consists in treating another human being as a thing."

    John Brunner, "The Shockwave Rider".