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

Hello Everyone,

I'm trying to figure out how to capture the return code of the previous command. The command is being invoked by the system call. I'm importing large amounts of data into a MySQL database. I'm having to convert logfiles for importation into the database. The original file was over 2 Gig so it was hard to look for out of the ordinary patterns... I had to split the files as it was causing MySQL to error out. I created a perl script (shown below) that will import the files then sleep for 5. As there are over 2300 files I need to know which ones are balking:

$LIST_FILE="listfile2"; open(LISTFILE, "$LIST_FILE") or die "Can't open the file.\n"; while(<LISTFILE>) { $FILE=$_; # Let's do it print "Importing $FILE.\n"; system("mysql < $FILE"); print "Sleeping for 5.\n"; system('sleep 5'); }
This actually is being run on an NT system where the database resides (I've set up a Samba share). I know both Windows shell scripting and Unix shell scripting. I'm aware of both the %ERRORLEVEL% and $? values but do not know if these will work. I thinking simplicity here. If the exit code is other than zero, then write the name of the file to a log file (a bonus would be to acutally capture the error itself). I had tried to redirect both 2>> errorlog and 2&>> errorlog in the:
system("mysql < $FILE 2>> errorlog"); system("mysql < $FILE 2&>> errorlog");
Can anyone help me out?

20041011 Edit by ysth: add p and code tags

Replies are listed 'Best First'.
Re: Need to capture return code
by Roy Johnson (Monsignor) on Oct 11, 2004 at 19:00 UTC
    I'm aware of both the %ERRORLEVEL% and $? values but do not know if these will work.
    Why would you think that $? might not work? It is documented as
    The status returned by the last pipe close, backtick (``) command, successful call to wait() or waitpid(), or from the system() operator.
    For redirecting your output, the syntax you're using is Unix shellian. It shouldn't work on NT. You can reopen STDOUT and STDERR, though, prior to the system calls, and restore the old file handles as necessary:
    open my $oldout, '>&STDOUT' or die "Duping STDOUT: $!\n"; open my $olderr, '>&STDERR' or die "Duping STDERR: $!\n"; open my $log, '>errorlog' or die "Opening errorlog: $!\n"; while(<LISTFILE>) { chomp($FILE=$_); # You do probably want to remove the newline # Let's do it print "Importing $FILE.\n"; open STDOUT, '>&', $log or die "Redirecting STDOUT: $!\n"; open STDERR, '>&', $log or die "Redirecting STDERR: $!\n"; system("mysql < $FILE"); open STDOUT, '>&', $oldout or die "Restoring STDOUT: $!\n"; open STDERR, '>&', $olderr or die "Restoring STDERR: $!\n"; print "Sleeping for 5.\n"; system('sleep 5'); } close $log;

    Caution: Contents may have been coded under pressure.
Re: Need to capture return code
by pg (Canon) on Oct 11, 2004 at 19:45 UTC

    With $?, you have to be careful that, its value is not exactly what returned from sub process, but $? >> 8 is.

    Try this out with those two pieces of code:

    system("perl -w c.pl"); print $? >> 8, "\n"; #this gives you 10 print $?; #this gives you 2560

    c.pl:

    exit 10;
      That statement looks like a redirect into a file (in Unix and NT)?

      print $? >> 8, "\n"; #this gives you 10 print $?; #this gives you 2560

      OOPS, I meant ->I'm not familiar with this obviously ($?>>8)
      Okay I did a search and found it shifts it over 8 digits
Re: Need to capture return code
by periapt (Hermit) on Oct 12, 2004 at 12:31 UTC
    The Perl system command gives the return code of the process call in the upper byte of a two byte word. Right shifting this code 8 bits will give you the return code of the operation.
    ... # some code print "Importing $FILE.\n"; $rtncd = system("mysql < $FILE") >> 8; # shift right 8 bits to recov +er actual code if($rtncd == 0){ ... # everything OK }else{ ... # some problem ? } print "Sleeping for 5.\n"; system('sleep 5'); ... #more coce
    If you want to capture the output of the mysql call, use backticks or qx// such as $rtncd = `mysql < $FILE`;. Often, when the actual program return code isn't helpful (for example my program fails gracefully which annoyingly produces a clean return code of 0) I have the program print an error message or error code and then capture that output via backticks. It works pretty well.

    PJ
    use strict; use warnings; use diagnostics;
Re: Need to capture return code
by dragonchild (Archbishop) on Oct 11, 2004 at 18:33 UTC
    Is there a reason you're not just running $LIST_FILE directly through mysql?

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      This is my first post
      Listfile is the list of files that are to be imported (not the actual data). I'm calling each file then importing the specific file. I'm not MySQL expert either so if there's a way to tell it to import various numbers of files I'd like to know .
        Well, your code isn't doing that. Your code is saying that you have a list of MySQL commands in listfile2 and you're running through those commands one by one.

        Being right, does not endow the right to be rude; politeness costs nothing.
        Being unknowing, is not the same as being stupid.
        Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
        Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.