views:

893

answers:

3

I am trying to invoke a bat file from a perl script as follows:

 system("call D:/SIP/run_$file_idx.bat");

However I observe that the environment variables in the bat fail to get resolved. If I run the bat file separately from the command prompt it works.

Does system() create a new environment and execute bat file in that? What is that I am missing?

if (($ENV{'IPSL_RUN_FLAG'}) eq "TRUE") {

my $Book = $Excel->Workbooks->Open(
    "$ENV{'IPSL_TESTCASES_PATH'}IPSLFeatureLoadRunResults.xls"); 

# Make transparent where the IPSL tarball is installed. 
# Have ControlPanel save results here.

# You can dynamically obtain the number of worksheets, rows, and columns
# through the Excel OLE interface.  Excel's Visual Basic Editor has more
# information on the Excel OLE interface.  Here we just use the first
# worksheet, rows 1 through 4 and columns 1 through 3.

# select worksheet number 1 (you can also select a worksheet by name)

my $count=0;

my $Sheet = $Book->Worksheets("LOADDATA");
my $tmp=0;


foreach my $row (13..776) {
    foreach my $col (17..17) {
        if(($Sheet->Cells($row,$col)->{'Value'} eq "Failed") || 
            ($Sheet->Cells($row,$col)->{'Value'} eq "No Run") ) {
            $cnt_of_current_rerun_testcases++;
            foreach my $col (18..18) {
                # skip empty cells
                next unless defined $Sheet->Cells($row,$col)->{'Value'};
                my $a = $Sheet->Cells($row,$col)->{'Value'};

                my $i = index($a, 'run');  
                $a = substr($a, 0, $i); #remove runTest*  

                print OUT "\n";
                if($count == 0) {
                    print OUT "\nREM "; 
                    print OUT  "*" x 100; 
                    print OUT "\n";
                    print OUT "\ntaskkill /F /FI \"USERNAME eq %USERNAME%\" /IM ips32.exe";
                    print OUT "\ntaskkill /F /FI \"USERNAME eq %USERNAME%\" /IM ipsldb.exe";
                    print OUT "\ntaskkill /F /FI \"USERNAME eq %USERNAME%\" /IM ipsltiu.ex\n";    
                }

                print OUT "c:\n";            
                print OUT "\ncd ";

                $a =~ s/%I/\"%I/g;
                $a=~s/H%/H%\"/g;

                print OUT " $a\n";

                print OUT "\n";
                print OUT "CALL run_SubscribeFeatureOnHIQ.bat";
                print OUT "\n";

                print OUT "sleep 10\n";

                print OUT "\ncd ";
                print OUT " $a\n";
                print OUT "\n";

                print OUT "CALL ";
                $i=$Sheet->Cells($row,$col)->{'Value'};
                $i=~ s/%I/\"%I/g;
                $i=~s/H%/H%\"/g;
                print OUT $i;
                #print OUT  $Sheet->Cells($row,$col)->{'Value'};
                print OUT "\n";

                $count++;
                if($count == $no_simul_tcases) {
                    $sleep_cnt++;
                    print OUT "echo Going for sleep $sleep_cnt\n";
                    print OUT "SLEEP 300";
                    print OUT "\n";
                    $count=0;
                }
            }
        }
    }
}

print OUT "\ntaskkill /F /FI \"USERNAME eq %USERNAME%\" /IM ips32.exe";
print OUT "\ntaskkill /F /FI \"USERNAME eq %USERNAME%\" /IM ipsldb.exe";
print OUT "\ntaskkill /F /FI \"USERNAME eq %USERNAME%\" /IM ipsltiu.ex\n";         
print OUT "\nset IPSL_RUN_FLAG=TRUE";
close OUT ;
system(\"start $ENV{'IPSL_TESTCASES_PATH'}SIP\\run_$file_idx.bat\");

And the batch file is:

taskkill /F /FI "USERNAME eq %USERNAME%" /IM ips32.exe
taskkill /F /FI "USERNAME eq %USERNAME%" /IM ipsldb.exe
taskkill /F /FI "USERNAME eq %USERNAME%" /IM ipsltiu.ex
c:

cd  "%IPSL_TESTCASES_PATH%"SIP\TestCASE\FEATURESINT\INT_cfSRS\INT_cfSRS_cfSERRNG\

CALL run_SubscribeFeatureOnHIQ.bat
sleep 10


cd  "%IPSL_TESTCASES_PATH%"SIP\TestCASE\FEATURESINT\INT_cfSRS\INT_cfSRS_cfSERRNG\

CALL "%IPSL_TESTCASES_PATH%"SIP\TestCASE\FEATURESINT\INT_cfSRS\INT_cfSRS_cfSERRNG\runTest_SRS_INT_SERRNG.bat

Possible workaround:

By using exec and specifically writing the ENV into bat file gave me a workaround:

print OUT map { "set $_=$ENV{$_}\n" } 
          qw( path USERPROFILE USERNAME ProgramFiles ComSpec APPDATA );

The issue is still seen with system() though. I tried Sinan's suggestion in the answerers..

A: 

The system command [contested: /function] will start your batch script in the default batch file context (which is the system-wide environment), if your parameter to the system call is a scalar. It is basically the same as starting the command using "cmd /c myfile.bat". If your argument to system() is an array [contested: /list], you will not have this problem. Please read this for more information.

Ludvig A Norin
I don't see the point of linking to a site that gives incomplete information that has nothing whatsoever to do with the OP's problem other than to give them Google juice and increase their ad revenue. Earlier, I had directed the link to official Perl documentation. Now, flagging your post as spam.
Sinan Ünür
Sinian, are you being directed to a spam site when clicking that link, or an overview of how to start external commands in perl? The site may not be to your liking, not the best or even correct - but you should respect my answer anyway (and downvote it, comment on it, as is the way things goes, if you wish). As for the correctness, the actual bug seems to be that he is using 'start' in his code (which wasn't shown in the original question).
Ludvig A Norin
Besides, nofollow is used on all links. There's no google juice to be gathered here.
Ludvig A Norin
Nope, `start` has nothing whatsoever to do with his problem as you can verify by running the batch file and short script I posted. Your answer is incorrect because the distinction you claim between the scalar versus list arguments to `system` is imaginary. To see the importance of linking to correct documentation rather than some ad-harvester's idea of how things work, compare the way the success of the `system` call is checked on the page you link versus the way shown in the Perl docs.
Sinan Ünür
**Important clarification:** There is a distinction between providing a scalar versus a list argument to `system`. However, that has nothing to do with the environment inherited by the child process.
Sinan Ünür
A: 

Update 2: Let's look more closely at your system call:

 system(\"start $ENV{'IPSL_TESTCASES_PATH'}SIP\\run_$file_idx.bat\");

That should be syntax error and your script should not even be able to invoke the batch file. Try

 system(qq{start $ENV{IPSL_TESTCASES_PATH}SIP\\run_$file_idx.bat\\});

Update 1: Looking at the code you posted, you are using start in the system call. That starts a new cmd.exe process and that cmd.exe will remain long after your script has terminated. However, I still do not observe behavior as you describe and I am going to look at your code dump more closely.

C:\Temp> cat bg.bat
@echo %YAEV%
@echo %*
C:\Temp> cat t.pl
#!/usr/local/bin/perl

use strict;
use warnings;

$ENV{YAEV} = 'Yet another environment variable';
system 'start bg.bat "This is a test"';

In a new cmd.exe window:

C:\Temp> t
Yet another environment variable
"This is a test"
Sinan Ünür
+1  A: 

Child processes inherit the environment of their parent. The bat file should have the same environment as the Perl script. If you haven't setup the environment correctly, your bat file won't see it.

Can you expand your answer to show your test case, similar to what Sinan has done? Although you say in your comment that the code is simple, that is never true. Show us the complete Perl program you have and the complete bat file that you have. Don't make us guess or do a lot of work to figure out what you are doing.

Update: Now that you've provided some code, start cutting parts out of it to make the simplest test case that still shows the problem. When you are investigating these sorts of problems, stop working on the big script and write a little script that exercises the problem you think you're having. That way, you isolate it from everything else you might be messing up.

brian d foy