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,
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.my @cmd = ('someprog', 'somearg', 'anotherarg'); my $msg = qx/@cmd 2>&1/;
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!
In reply to Re: Using system(): converting error num to human readable message
by naikonta
in thread Using system(): converting error num to human readable message
by chrism01
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |