http://www.perlmonks.org?node_id=625466


in reply to Re^4: $? set to strange values on failure under Win32
in thread $? set to strange values on failure under Win32

BrowserUk/Rob, your responses are gold. Your answers are exactly the sort of information I was after.

However it appears that $^E isn't yet my saviour. Under my Windows XP system I get the following results (uninitalized warnings trimmed):

#! perl -slw use strict; undef $^E; undef $!; print 'Successful command returning 1'; system 'c:/perl/bin/perl.exe -e"sleep 5; exit 1"'; print "![$!] ?[@{[$?, ':', $?>>8]}] E[$^E]"; undef $^E; undef $!; print "\nNonexistent command, attempted direct but fallback to via cmd +"; system 'c:/doesNotExists.exe'; print "![$!] ?[@{[$?, ':', $?>>8]}] E[$^E]"; undef $^E; undef $!; print "\nNonexistent via cmd because 'shell chars'; sending stderr >nu +ll"; system 'c:/doesNotExists.exe 2>null'; print "![$!] ?[@{[$?, ':', $?>>8]}] E[$^E]"; __END__ Successful command returning 1 ![] ?[256 : 1] E[] Nonexistent command, attempted direct but fallback to via cmd 'c:/doesNotExists.exe' is not recognized as an internal or external co +mmand, operable program or batch file. ![No such file or directory] ?[256 : 1] E[] Nonexistent via cmd because 'shell chars'; sending stderr >null ![] ?[256 : 1] E[]

It appears that redirecting stderr makes an unsuccessful command appear to be a successful command. When an error does occur, it's found inside $! and not $^E, which seems to never be set. Oh my!

Unfortunately this leaves me with the same tangle as Perl itself has in emulating system() under Windows. Ideally I want to preserve the following behaviours:

  1. Single argument call always goes via the shell
  2. Multi argument call never goes via the shell
  3. It's possible to tell when a command didn't start (ostensibly via $? being set to -1)

Using the shell means I don't have a reliable way of determining failure to start a command. Not using the shell means I may have to potentially go searching through $ENV{PATH} by hand.

I guess this is an excellent opportunity for me to go searching for that discussion by tye, and potentially go looking through Perl's source for system() under Windows. I suspect my final result will make heavy use of Win32:: modules to provide the required behaviour.

Many thanks again!

Update: Working with Win32::Process is showing great promise.

Replies are listed 'Best First'.
Re^6: $? set to strange values on failure under Win32
by syphilis (Archbishop) on Jul 08, 2007 at 01:21 UTC
    When an error does occur, it's found inside $! and not $^E

    Could $! then be used (instead of $^E) to determine the info you need ? Looking at what you, BrowserUk, and I have posted, it seems that $! might be all you need to consider (so long as it's undeffed before the system call). Or am I missing something ?

    Cheers,
    Rob
    Update: I have no problem with Paul's preference for Win32::Process. The variablility in $^E and $!, wrt to system(), doesn't inspire a lot of confidence.

      Using $! may be a possibility, but I've decided that moving with your suggestion of Win32::Process is better. It appears to be more consistent across operating systems, it allows us to access the whole 16 bits of the command's return value, it can be used to check if the command was successfully executed, and (at least on my system) it sets $^E to a meaningful value on failure.

      I've also discovered that my problem isn't unique to Windows. Under Unix, if Perl uses the shell then a value of 127 >> 8 is placed into $? on failure to find the command, which is indistinguishable from the command completing with a return of 127. Fundamentally, whenever we invoke the shell, we lose the ability to tell the difference between our final command failing to spawn, or spawning but returning a funny value. One should stress the wisdom of avoiding commands that return 1 under Windows, or 127 under Unix.

      It appears that Windows will still try to invoke the shell even if called with a multi-argument system(), whereas under Unix this never happens.

      The whole thing is still a huge pain for what I'm trying to achieve, but at least it's a (mostly) consistent huge pain across platforms.