5

can we source a shell script in the perl script??

Example: Program 1:

cat test1.sh
#!/bin/ksh
DATE=/bin/date

program 2:

cat test2.sh
#!/bin/ksh
. ./test1.sh  
echo `$DATE`

Program 3:

cat test3.pl
#!/usr/bin/perl
### here I need to source the test1.sh script
print `$DATE`'

How to source the shell in perl to get the date printed when I execute test3.pl

thanks raghu

Chas. Owens
  • 64,182
  • 22
  • 135
  • 226
raghu
  • 51
  • 1
  • 1
  • 2
  • any reason why you don't want to use Perl's date time modules for this? – ghostdog74 Sep 09 '10 at 10:43
  • 1
    @ghostdog74 You don't even need a module. The `localtime` function in scalar context produces an almost identical string: `perl -le 'print scalar localtime'`, you just need to get the timezone and they will be identical. – Chas. Owens Sep 09 '10 at 10:54
  • Hey Date is just an example ... it can be any thing in the place of the date (ls,chown,echo .....) what ever the command may be in the first file i need to source to the perl; – raghu Sep 16 '10 at 11:43

7 Answers7

4

You cannot do a

system("source src.sh");

system() starts a new sub-shell, your environment variables do not get passed to the shell your Perl script is running in. Even though your shell script exports variables, it will export them to the sub-shell, not to your actual shell.

One solution would be to write a wrapper script which

  1. First sources the shell script and then
  2. Runs the Perl script
codaddict
  • 445,704
  • 82
  • 492
  • 529
  • 1
    This is what I generally do, but it doesn't work if you want to source different files depending what you are doing. For instance, lets say you have three databases and need different environments to access them. You don't know in advance which database you will need to connect to. In cases like that the wrapper method falls down. – Chas. Owens Sep 09 '10 at 10:51
2

Yes, you can now do this with the Env::Modify module.

use Env::Modify qw(:ksh source);
source("./test1.sh");     # env settings from test1.sh now available in Perl
print `$ENV{DATE}`;       # print `/bin/date`;
mob
  • 117,087
  • 18
  • 149
  • 283
1

You can do something simple, like this:

system "source /path/to/shell_env.sh &&"
     . "/path/to/script.sh";

NOTE that this is different than the following which is not recommended:

   system "source /path/to/shell_env.sh &&"
        . "/bin/sh /path/to/script.sh";
Joey
  • 11
  • 1
1

I don't know that this will help, but I felt compelled to come up with a way to write this in Perl. My intent was to have Perl run a shell script, and to assign any shell variables it sets to like-named variables in the Perl script.

The others are correct in that any shell script you "source" is going to be in a sub-shell. I figured I could use "sh -x cmd" to at least have the shell show the variables as they're set.

Here's what I wrote:

use strict;  use warnings;

our $DATE;

my $sh_script = "./test1.sh";

my $fh;
open($fh, "sh -x '$sh_script' 2>&1 1>/dev/null |") or die "open: $!";
foreach my $line (<$fh>) {
    my ($name, $val);
    if ($line =~ /^\+ (\w+)='(.+)'$/) {  # Parse "+ DATE='/bin/date;'
        $name = $1;
        ($val = $2) =~ s{'\\''}{'}g;  # handle escaped single-quotes (eg. "+ VAR='one'\''two'")
    } elsif ($line =~ /^\+ (\w+)=(\S+)$/) {  # Parse "+ DATE=/bin/date"
        $name = $1;
        $val = $2;
    } else {
        next;
    }
    print "Setting '$name' to '$val'\n" if (1);
    # NOTE: It'd be better to use something like "$shell_vars{$name} = $val",
    #  but this does what was asked (ie. $DATE = "/bin/date")...
    no strict 'refs';
    ${$name} = $val;    # assign to like-named variable in Perl
}
close($fh) or die "close: ", $! ? $! : "Exit status $?";

print "DATE: ", `$DATE` if defined($DATE);

There's certainly more error-checking you could do, but this did the trick for me if all you want to catch is shell variables.

Michael Krebs
  • 7,951
  • 1
  • 21
  • 17
1

I met a close need from the OP's in a project, where I needed to configure a Perl script (it could be any language, for that matter) by sourcing a shell script defining the environment.

I personally rarely use sourcing for anything else than configuration and environment setting (the only other good reason for sourcing I am aware of, is for importing functions in shell scripts, but I may be missing some creative usage).

My solution was to source the configuration script from a launcher script (in shell), and then to exec the Perl script in the same launcher script (replacing effectively the launcher script by the Perl script, thus avoiding to create a subprocess).

# configuration_script.sh
export MY_ENV_VAR1=value1
export MY_ENV_VAR2=value2

# launcher_script.sh
. configuration_script.sh # source the configuration
exec /path/to/main_script.pl "$@" # could be any other language here (Python, Tcl, Ruby, C, Java...)

The "$@" allows to pass the command line arguments from the launcher script to the main script.

It's then up to the main script author to retrieve the environment (e.g. with $ENV{MY_ENV_VAR1} in Perl).

Corentor
  • 661
  • 1
  • 6
  • 11
0

You can't source shell files in Perl 5. Sourcing is literally running the commands in the shell file in the target shell; however, it is trivial to open and read the file:

#!/usr/bin/perl

use strict;
use warnings;

use Carp;

sub source {
    my $file = shift;
    open my $fh, "<", $file
        or croak "could not open $file: $!";

    while (<$fh>) {
        chomp;
        #FIXME: this regex isn't quite good enough
        next unless my ($var, $value) = /\s*(\w+)=([^#]+)/;
        $ENV{$var} = $value;
    }
}

source "./test1.sh";

print "$ENV{DATE}\n";
Chas. Owens
  • 64,182
  • 22
  • 135
  • 226
0

Uhm.. is the below cheating?

#!/bin/sh
. ./test1.sh # source the test script
echo Bash says $DATE
export DATE;      # KEY to have the below Perl bit see $ENV{DATE}
perl <<'ENDPERL';
    print "Perl says $ENV{DATE}\n";
ENDPERL

The problem is that sourcing the sh file may do whatever, and not just assign value X to variable Y...

mfontani
  • 2,924
  • 20
  • 18