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

I am trying to run a shell script from a perl script. The shell script resides in a different folder. I am using the following code.

$cmd = "cd /home/folder1/folder2 ; sh test1.sh"; system($cmd) or die "none";

I am getting the below message after execution. none at ./test3.pl line 12. Kindly help on this.

Replies are listed 'Best First'.
Re: Calling a shell script after changing directory
by salva (Canon) on May 11, 2016 at 07:03 UTC
    As haukex says, system is a bit special in that it returns 0 on success. A common way to handle that is as follows:
    system($cmd) and die "command failed with code " . ($? >> 8).

    Also, in order to chain several commands into a single shell call it is better to use && instead of the semicolon. That way, if some command fails, processing stops immediately.

    $cmd = 'cd /home/folder1/folder2 && sh test1.sh';
Re: Calling a shell script after changing directory
by Discipulus (Canon) on May 11, 2016 at 07:05 UTC
    ... or you can invoke the external script with a full path, as in
    system 'sh /home/folder1/folder2/test1.sh';

    But you are doing something very wrong, which is the cause of your error: system($cmd) or die "none"

    Infact system is not like open from the docs:

    The return value is the exit status of the program as returned by the wait call. To get the actual exit value, shift right by eight (see below). See also exec.

    system sets $? and if you need to inspect the returned status you need something like this (again from the docs):

    if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } else { printf "child exited with value %d\n", $? >> 8; }

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Thanks mate. That was of great help. When I inspect $?, I can see that it possess the value '0' after executing the system call. That means the system call was successful if I am not wrong. Even after that I can see that the environment variables are not set (as mentioned in my previous comment while replying to Hauke).
        read salva's answers: they are always worth to read carefully.

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Calling a shell script after changing directory
by haukex (Archbishop) on May 11, 2016 at 06:50 UTC

    Hi Gouravhere,

    You could use chdir to change the directory before executing the script, or perhaps File::pushd to easily restore the original working directory.

    However, are you sure your script is failing? Have a look at the documentation of system for its return value and error handling: the convention is that an exit code of zero means success, so if your test1.sh follows this convention (which I'd strongly recommend), then the correct way to check for errors is system(@args) == 0 or die ....

    Hope this helps,
    -- Hauke D

      Hi Hauke, Thanks for your reply. I can see that the script is failing. I am actually executing a shell script which sets environment variables. Now after executing the script I cant see the variables. Also you can see that the process is getting halted as it encounters  die which I kept right after the system call. Regards, Gourav
        I am actually executing a shell script which sets environment variables

        That is not going to work. The scope of environment variables is not global but limited to the process where they are set and subprocesses forked from it which inherit them.

        In your code, system launches a shell that starts a new shell for executing test1.sh. Any environment variable set in the script just lives until the second shell terminates.

        A possible way to work around that is to dump the variables from the shell before it terminates. For instance:

        # untested; my $set_env = `cd $dir && source test1.sh && perl -MData::Dumper -e 'p +rint Dump \\\%ENV'` and die; print $set_env;