in reply to Using system(): converting error num to human readable message

First of all, $? and $! are two different things and they're not correlated. The $? comes from executing external program, and this external program may exit with arbitrary number (except 0, which is for success or true) when error occures. The $! comes from running a system call such as but limited to open, sysread, and socket. The $! can be used in either numeric or string context. All $! values and their counterpart strings are defined by the C library of underlying system, so you can't just set $! at will, unless you know what you're doing.

To find out what $? of a given external command really means you have to read its respective manual like one what ls says:

Exit status is 0 if OK, 1 if minor problems, 2 if serious trouble.
And we use the shift operator on $? to find whether it's 1 or 2 in this case. If that's 1 for example, we know that there's a minor problem, but that's all you can get. While external programs spits out their arbitrary error code that gets set in $?, they might throw the equally arbitrary error message (mostly) to the standar error (STDERR). So you see that error code ($?) and error message are not relevant. What make thing worse is that every program in the system has their own idea about what error code to use and how many of them. And not all of them are documented. Shortly, this isn't something you can rely on. The $! is, in contrast, well defined by the C Errno library so it's portable across systems using the same C libs.

So that hopefully answers to your number "1. Why?". As for the number 2, I gave a hint in the explanation above about error message is thrown to STDERR. So, in order to get the error message you have to capture it from STDERR. One (in)famous way and the short answer is with the bactick operation. But the perldoc -q capture will give you the long and more descriptive answer. Or, you can go here. For example,

my @cmd = ('someprog', 'somearg', 'anotherarg'); my $msg = qx/@cmd 2>&1/;
The 2>&1 bit tells the system to include whatever thown to STDERR to STDOUT. But again, you first check whether is error or not by checking $?. If it's non-zero, then error occures and $msg contains the error message thrown by someprog. The backtick operation is there for capturing output, in contrast with system. But both are for executing external/shell programs. Let me make clear that 2>&1 is not part of Perl syntax whatsoever, it's a shell construct.

I want to also suggest that instead of writing if( $status != 0 ) {}, you can write,

if ($?) { # error occures # do whatever }

A side note: Years ago in my early Perl programming days, I used to play a lot with external program using system and backtick operation. My favourite program was useradd. It documents a number of error codes. So you may guess what I was doing with useradd and friends in Perl ;-)

See also: perlvar, system, perlop, STDERR


Update: Added note about 2>&1 being a shell construct.


Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

Replies are listed 'Best First'.
Re^2: Using system(): converting error num to human readable message
by chrism01 (Friar) on Apr 18, 2007 at 04:48 UTC
    Actually, i do know the diff between shell and Perl, I've been programming for a few yrs now.. ;-)
    From what you two are saying, it sounds like it's impossible to do what I want anyway.
    I tried your use of qx, but it failed thus:
    @cmd_arr = ("someprog", "var"); $msg = qx/@cmd_arr 2>&1/; if( $? ) { print "fail $?\n"; print "$msg\n"; } Result: fail -1 Use of uninitialized value in concatenation (.) or string at ./err_cvt +.pl line 17.
    I read about the $? >> 8 in the Cookbook and I read the info about $! in a string context in perlvar http://perldoc.perl.org/perlvar.html#%24ERRNO, which is why I was trying to use those techniques.
    I like to check rtn status' as much as possible and I've always hated the fact I can't get reliable sensible msgs from system(), so I thought I'd ask if there was a known solution.
    Apparently not ... :-(

    Cheers
    Chris

    PS any idea on Qn 3 ?

      I didn't mean to say that everytime you do $msg = qx/prog 2>&1/ you always get error message in $msg because the error message totally depends on the program in question. In fact, your example shows that your execution on "someprog" doesn't say anything at all so $msg remains undefined, hence the warning message.

      Take a real progam as example,

      $ perl -wle '$msg = qx/ls -K 2>&1/; print "error: $?"; print $msg' error: 512 ls: invalid option -- K Try `ls --help' for more information.

      If what you meant is that you want to capture the error on the fact that "someprog" command doesn't exist on the system, then you need to capture the error of the shell, not "someprog". Well, depending on your shell,

      $ perl -wle '$msg = qx/bash -c ProgramNotExist 2>&1/; print "error: $? +"; print $msg' error: 32512 bash: ProgramNotExist: command not found

      Update: Rephrased the "In fact, ...." sentence.


      Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!