Perl Index function not working? - perl

I'm trying to test if a backtick output string (it is a string, right??) contains a substring.
my $failedCoutner = 0;
my $tarOutput = `tar -tvzf $tgzFile`;
print "$tarOutput\n";
my $subStr = "Cannot open: No such file or directory";
if (index($tarOutput, $subStr) != -1)
{
push(#failedFiles, $tgzFile);
$failedCounter++;
print "Number of Failed Files: $failedCounter\n\n\n";
}
print "Number of Failed Files: $failedCounter\n\n\n";
But this isn't working. It never enters the if statement.
The backtick output:
tar (child): /backup/Arcsight/EDSSIM004: Cannot open: No such file or directory
tar (child): Error is not recoverable: exiting now
tar: Child returned status 2
tar: Error is not recoverable: exiting now
Number of Failed Files: 0
Clearly the substring is in the first line. Why won't it recognize this??

tar, like most programs, writes error messages to STDERR. That's the purpose of STDERR.
Backticks only capture STDOUT.
You could redirect tar's STDERR to its STDOUT, but why not just check its exit code.
system('tar', '-tvzf', $tgzFile);
die "Can't launch tar: $!\n" if $? == -1;
die "tar killed by signal ".($? & 0x7F) if $? & 0x7F;
die "tar exited with error ".($? >> 8) if $? >> 8;
Advantages:
Catches all errors, not just one.
The output isn't held up until tar finishes before being sent to the screen.
It solves the problem of archives with shell metacharacters (e.g. spaces) in their name without invoking String::ShellQuote's shell_quote.

Check if backticks produced an error with $?:
use warnings;
use strict;
my $tarOutput = `tar -tvzf doesnt_exist.tar.gz`;
if ($?) {
print "ERROR ... ERROR ... ERROR\n";
}
else {
# do something else
}
__END__
tar (child): doesnt_exist.tar.gz: Cannot open: No such file or directory
tar (child): Error is not recoverable: exiting now
tar: Child returned status 2
tar: Error is not recoverable: exiting now
ERROR ... ERROR ... ERROR

Related

error in system command to output

I want to run ext software (hmmer) commands through perl in a loop for input files (in linux).
I used this line
system "hmmbuild $outfile $files";
where $outfile is my output file and $files in my input files. hmmbuild is the command for the ext software.
When I run the program it gives me error code for the output file GLOB(0x1b94b220).
Can any one help me where I am wrong and how can it be corrected?
I tried exec command also with back tick and brackets.
This is the exact output message i got. How can I print my result to output file ($outfile)?
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `hmmbuild --amino GLOB(0x11eb3220) aproNOG00001'
script goes here..
#!/usr/bin/perl
use Bio::AlignIO;
use Bio::Align::AlignI;
my $allfiles= 'allfilenames_alpha_hmms.txt';
system "module load hmmer/3.1b1";
print "loaded hmmer\n";
open(FIH, $allfiles);
while ($min=<FIH>)
{ chomp($min); my #pats=split " ",$min;
foreach my $files(#pats) {
print $files; print "\n";
open(my $outfile, '>',"$prefix.hmm");
system "hmmbuild --amino $outfile $files";
print $outfile;
print "file saved\n";
# }
}
}
print "\n\n\n\t ###\tDONE\t### \n\n";
how can i print my result to output file ($outfile)
I take it hmmbuild expects a path to a file? Pass the path to the file rather than what's in $outfile.
system "hmmbuild --amino $prefix.hmm $files";

perl system call doesn't call ksh script

I am trying to call a ksh script from my PERL script but am unable to do so.
Here's my command
$cmdString = “/path to script/lookupCal.ksh --service 2 -i /auto/dataprod/MSUkeyDates -f /auto/dataprod/HoursOfOpData --timezone America/New_York”
system($cmdString)
All I am doing is sending an input file of Msymbolukeys to get an output file with their hours of operation (which will be in HoursOfOpData after the ksh script runs) which I read later in my PERL code.
When I run this from the command line, it works as expected but the call from my PERL script doesn't seem to call the ksh script.
I tried adding some debug statements
if(system($cmdTmpstr) != 0)
{
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;
}
}
This is the output I get from the logs
**child died with signal 11, without coredump**
Any tips to fix this?
Does this help?
my #cmd = (
"/path to script/lookupCal.ksh",
"--service", 2,
"-i", "/auto/dataprod/MSUkeyDates",
"-f", "/auto/dataprod/HoursOfOpData",
"--timezone", "America/New_York"
);
system #cmd;

change in $? after the call to close in perl

Following is the code
use strict;
use warnings;
my $cmd = "ls";
my $pid = open(INPUT,"$cmd 2>&1 |");
print "PID = [$pid] [$?]\n";
if (!defined($pid)) {
print "PID not defined\n";
} else {
print "BEFORE CLOSING exit code is [$?]\n";
}
close INPUT;
print "AFTER CLOSING [$?]\n";
The output is as follows :
PID = [32300] [0]
BEFORE CLOSING exit code is [0]
AFTER CLOSING [13]
Why the value of $? changes after the call to close()?
According the documentation of perl close:
...
Closing a pipe also waits for the process executing on the pipe to exit--in case you wish to look at the output of the pipe afterwards--and implicitly puts the exit status value of that command into $? and ${^CHILD_ERROR_NATIVE}.
...
So in you example, $? contains the exit status of the command ls
perlvar says that $? is:
The status returned by the last pipe close, backtick (`` ) command, successful call to wait() or waitpid(), or from the system() operator.
So clearly it has to reflect the status of your pipe close. Before any of these operations its contents are meaningless.

Perl: Capturing correct return value from 'system' command

I'm a beginner in Perl. I have a Windows batch script which contains multiple NMake commands. An existing issue with this batch script is that even if the NMake command fails during its execution, ERRORLEVEL doesn't get set properly.
So we never know whether the command worked until we parse the log file. I looked into it but couldn't find a solution. I, then thought of converting this batch script to a Perl script assuming that trapping error will be easier but it seems it's not that easy :)
Whenever I run my Perl script, the 'system' command always returns 0. I looked at many different links, and realized that capturing the correct return status of 'system' command is not that straightforward. Still, I tried the suggestions but things are not working. :(
Let me mention that the NMake command that is called, in turn, calls many different commands during its execution. For instance, the command output mentioned below, which is throwing 'fatal error', is actually part of a Perl script (check_dir.pl). This call to Perl script is written in the NMake file itself.
If I call this Perl file (check_dir.pl) directly and check for exit value, I get correct result i.e., the command fails and prints a non-zero exit value (...unexpectedly returned exit value 2).
Tried Perl's system function but it didn't help. I used the following code:
system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");
if ( $? == -1 ) {
print "Command failed to execute: $!\n";
}
elsif ( $? & 127 ) {
printf "The child died with signal %d, %s a coredump\n",
( $? & 127 ), ( $? & 128 ) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
Output:
.....
.....
Unable to open dir: R:\TSM_Latest
Compressing...NMAKE : fatal error U1077: 'if' : return code '0x2'
Stop.
child exited with value 0
Also tried:
use IPC::System::Simple qw(system);
my $exit_status = system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");
if ($exit_status != 0) {
print "Failure";
exit 3;
} else {
print "Success";
}
Finally tried the following module:
use IPC::Run qw( run timeout );
run "nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1" or die "NMake returned $?";
Nothing seems to be working :(
Please correct me if i'm interpreting the return value of system incorrectly.
You have:
use IPC::System::Simple qw(system);
my $exit_status = system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");
Given that you don't seem to care about the actual output, you can try
my $exit_status = systemx(nmake =>
qw(/f _nt.mak pack_cd),
"SUB_PLAT=$PLAT",
"DR=$plat",
);
To make sure you bypass cmd.exe and see if you get something useful.
For reference, the exit codes from nmake are listed here.
Running the following program:
use strict; use warnings;
use IPC::System::Simple qw(systemx);
use Try::Tiny;
my $status = 0;
try { systemx nmake => qw(/f bogus) }
catch { ($status) = ( /exit value ([0-9])/ ) };
print "Failed to execute nmake. Exit status = $status\n";
produces:
NMAKE : fatal error U1052: file 'bogus' not found
Stop.
Failed to execute nmake. Exit status = 2
The following version:
use strict; use warnings;
my $status = system nmake => qw(/f bogus);
if ($status) {
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;
}
}
produces:
NMAKE : fatal error U1052: file 'bogus' not found
Stop.
child exited with value 2
In fact, even when I use
my $status = system "nmake /f bogus";
I get the same correct and expected output.
Ditto when I use
my $status = system "nmake /f bogus 2>&1";
These observations lead me to the following questions:
Which version of nmake are you using?
Is the /I option in effect? Even though you don't set it from the command line, note the following:
/I Ignores exit codes from all commands. To set or clear /I for part of a makefile, use !CMDSWITCHES. To ignore exit codes for part of a makefile, use a dash (–) command modifier or .IGNORE. Overrides /K if both are specified.
So, I put together the following files:
C:\temp> cat test.mak
test.target: bogus.pl; perl bogus.pl
C:\temp> cat bogus.pl
exit 1;
And, ran:
use strict; use warnings;
my $status = system "nmake /f test.mak 2>&1";
if ($status) {
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;
}
}
which gave me the output:
perl bogus.pl
NMAKE : fatal error U1077: 'c:\opt\perl\bin\perl.EXE' : return code '0x1'
Stop.
child exited with value 2
where the last line shows that the exit status of nmake was correctly propagated.
Conclusion:
You have some other problem.
In fact, the OP later pointed out in comments that:
The actual command that i am trying to run is: system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1 | C:\\tee2 $TEMP_DIR\\modules-nt_${platlogfile}");
Given tees involvement in the pipeline, it is not surprising that nmakes exit code gets lost. tee is successfully able to process output from nmake, so it returns success, and that's the exit code your script sees.
Therefore, the solution is to capture the output of nmake yourself, either using qx (coupled with the appropriate level of error checking), or using capture from IPC::System::Simple. Then, you can decide to whether you want to print that output, save to a file, put it in an email etc …

perl invokes shell-- interrupt ^C stops the shell, not the perl

I want to use a Perl script to batch a repetitive operation which is invoked with system(). When something goes wrong and I want to interrupt this script, the ^C is captured by the shell, stopping whatever job, and the Perl script goes merrily along to the next one.
Is there a way I can invoke the job so that an interrupt will stop the Perl script?
You can check $? to see whether the command executed by system died from signal 2 (INT):
Here's a full example of parsing $?:
my $rc=system("sleep 20");
my $q=$?;
if ($q == -1) {
print "failed to execute: $!\n"
} elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($q & 127), ($q & 128) ? 'with' : 'without';
} else {
printf "child exited with value %d\n", $q >> 8;
}
# Output when Ctrl-C is hit:
# child died with signal 2, without coredump
Therefore the exact check you want is:
my $rc=system("sleep 20");
my $q=$?;
if ($q != -1 && (($q & 127) == 2) && (!($? & 128))) {
# Drop the "$? & 128" if you want to include failures that generated coredump
print "Child process was interrupted by Ctrl-C\n";
}
References: perldoc system for $? handling and system() call; perldoc perlvar for more details on $?
You are not checking the return value of system. Add to your parent program:
use autodie qw(:all);
and it program will abort as expected:
"…" died to signal "INT" (2) at … line …
You may catch this exception with Try::Tiny in order to clean-up on your own or use a different message.