in reply to Re: system and $?
in thread system and $?

You haven't mentioned what $! say

In this posting, I was mainly interested why system() does not adhere to the docs in that it does not return -1 on some platforms even the execution failed.

But - and maybe I should have mentioned this in my original post - the interest in this issue arose from a discussion with a co-worker about the proper usage of $!. My co-worker argued that it is never necessary to explicitly set $!=0 in a Perl program. His argument sounded convincing: $! (which is just errno) is only set if a low-level system call encounters a problem; otherwise, the value is not changed. Therefore, his argument goes, we first need to check if a function was successful, and only if it is not, we investigate $!. Example:

if(open(FOO,'<',$foo)) { ... } else { print "open $foo: $!\n"; }
This sounded convincing, but for the safe side, I tried to find a counter example, and came up with the example of system('myprog.exe'), where I can't, without prior setting of $!=0, reliably distinguish, whether or not myprog.exe has been executed with an exit code of 1, or could not be executed because it does not exist:

If myprog.exe can not be run, system(...) returns on my platform 256 (which is exit code 1, no child-error), and, as you point out, sets $! to some error code. But if myprog.exe can be run, and exits with code 1, I also get 256 as return code, and $! has an undefined value (it is set to whatever it had been set before the call to system). Only by explicitly setting it to 0 prior to running system(), is it that I can distinguish between those cases.

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re^3: system and $?
by Limbic~Region (Chancellor) on Aug 26, 2009 at 13:03 UTC
    rovf,
    I have never set $! in a program to set the exit status - I have always used exit for that.
    #!/usr/bin/perl # ... rest of program exit(0); # assuming everything went according to plan
    Does that not work on windows?

    Cheers - L~R

      I have never set $! in a program to set the exit status
      Of course you don't set $! to set the exit status!! You set $! to zero before a call to system(), in order to clear it. If system returns no error, but $! is set afterwards, you know that there must have been an error indeed. If you would not clear $! before the call to system(), you would not know afterwards whether there was an error in system(), or in some earlier function. For example, in the two following cases (on my platform), system returns the same value in both cases, and $! is also set in both cases, although only the first system() call actually failed:

      # On Windows 2000, ActiveState Perl 5.8.8 or 5.10 # case one: opendir(FOO,'.'); system('this_program_does_not_exist'); # $? == 256, $! != 0 # case two: opendir(BAR,'this_directory_does_not_exist'); system('perl -e "exit 1"'); # $? == 256, $! != 0
      But if you explicitly reset $!, you can distinguish between those cases:
      # On Windows 2000, ActiveState Perl 5.8.8 or 5.10 # case one: opendir(FOO,'.'); $!=0; system('this_program_does_not_exist'); # $? == 256, $! != 0 # case two: opendir(BAR,'this_directory_does_not_exist'); $!=0; system('perl -e "exit 1"'); # $? == 256, $! == 0

      -- 
      Ronald Fischer <ynnor@mm.st>
        rovf,
        Mea Culpa! I misunderstood and responded after only glancing at your reply before running off to a meeting. That'll teach me to drive by reply.

        Cheers - L~R

Re^3: system and $?
by ikegami (Patriarch) on Aug 26, 2009 at 13:59 UTC

    If myprog.exe can not be run, system(...) returns on my platform 256 (which is exit code 1, no child-error), and, as you point out, sets $! to some error code.

    You have a broken Perl if that's true.

    If myprog can not be run, system sets $? to -1 and sets the error in $!.

    If a shell command cannot be run, system sets $? to something other than -1 (since the shell was successfully executed) and $! contains no meaningful information. The shell cannot possibly change the parent's errno.

      By that logic, all windows perls are broken, which may or may not be true.

        It is broken in the sense that the shell is needlessly invoked. It probably does that because people expect `dir` to work. (dir is a shell command, not an executable.)

        But it does behave correctly for the shell being invoked.

        >perl -le"system 'foo'; print $?==-1 ? qq{$!=\$!} : qq{\$?=$?}" 'foo' is not recognized as an internal or external command, operable program or batch file. $?=256

        Unfortunately, that's all the information to which you have access. $! is meaningless. Conveniently, it does print an error message to STDERR.

        Update: This is even odder:

        >perl -le"system({ 'foo' } 'foo'); print $?==-1 ? qq{$!=\$!} : qq{\$?= +$?}" $?=65280
      You have a broken Perl if that's true.

      Well, it's pretty easy to reproduce, and the effect is the same in ActiveState 5.8.8 und 5.10. If I find the time, I'll try it with Strawberry...

      The shell cannot possibly change the parent's errno.
      Certainly not. It would need to communicate the information in a different way to the parent process. Well, this is a theoretical question, because Perl - likely in order to be portable - is not programmed that way, but: If it would be possible on Windows to somehow get the full (i.e. 32 Bit) Exitcode, we could use this information: If the shell can't execute a program, it sets this exitcode to 9009.

      OTOH, this would still make it indistinguishable from a program which deliberately sets that exit code..

      -- 
      Ronald Fischer <ynnor@mm.st>

        Well, it's pretty easy to reproduce, and the effect is the same in ActiveState 5.8.8 und 5.10.

        I used ActivePerl 5.10.0 b1005 above. 5.8.8 gives the same result. Both successfully execute the shell, so $? is not -1, so $! is meaningless.

        OTOH, this would still make it indistinguishable from a program which deliberately sets that exit code..

        Yes.