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

Hello Monks, I've stopped in to bother you with another take on what appears to be a common problem in hopes that someone here might have some insight. My OS is Win 2003 Server. First what works:
#! /usr/bin/perl use warnings; use strict; my $test = "/C \"C:\\Program Files (x86)\\Microsoft Office\\OFFICE11\\ +EXCEL.EXE\" C:\\test.xls"; system ("cmd",$test);
No problems here, even with the annoying windows long file name with spaces. The programs starts, the file is loaded, when i close the program I return to the shell and there are no errors. I've been using system this way for a long time and never seen a problem. Of course this is a gui program and doesn't even require cmd, so maybe in some weird way it's skipping right over it. However I can successfully run all kinds of cmd programs, for example:
my $testfile = "fromdos"; my $test = "/C ${testfile} test.txt"; system ("cmd", $test);
Now what doesn't work:
#! /usr/bin/perl use warnings; use strict; my $testfile = "resultset.exe"; my $test = "/C ${testfile} localhost root pwd"; system ("cmd", $test);
Now when this fails I get the classic "Can't spawn "cmd": Bad file descriptor at temp2.plx line 11." Line 11 being the system call. The test executable is in the directory with the perl script which calls it, and it requires the arguments listed in order to run. Run it does. However after the expected output I get the error. Even more strange is when I do this I get the same error:
my $test = "${testfile} localhost root pwd"; system ($test);
In this case I'm not even asking it to start cmd.exe, but yet it's telling me that it can't spawn it. Again, the executable runs and gives me it's output, but then I get the error. cmd.exe is in system32 where it should be and system32 is in my path (proven by the fact that the first code ran fine). The executable is in the same directory as this perl script. Thinking that this might be some weird sort of 32/64 bit issue, I also tried running it like this:
my $test = "/C ${testfile} localhost root pwd"; system ("C:\\WINDOWS\\SysWOW64\\cmd.exe", $test);
Same exact results. Anyone have a clue what is going on here? I think I've gone through all the usual suggestions concerning the path env and the windows/linux path variations. Nothing seems to change this behavior, and I think my first example bears out the fact that neither of these things are at the root of this. Thanks a Bunch

Replies are listed 'Best First'.
Re: Can't spawn "cmd.exe":
by almut (Canon) on Mar 18, 2009 at 04:35 UTC

    If the program does run and produce normal output, the message might be due to an incorrect interpretation of its status/return code1.  Maybe some variation of the issue discussed in What error is "No Error", where the problem seems to have been a negative return code of the program in question.  What return code do you get when you run the same command interactively from the command line?

    ___

    1  this is the respective snippet from Perl's win32.c where the warning (presumably) originates from:

    if (status < 0) { if (ckWARN(WARN_EXEC)) Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s +", argv[0], strerror(errno)); status = 255 * 256; }
      almut, I think you've hit the nail. I ran this manually from the CLI and then did echo %ERRORLEVEL% and the value returned was -1. Is this the proper way to check this? I wonder if you could remind me, in windows what would be the "normal" return code, 0 or 1?

      That's a very strange error message to return in the event of a negative return code. Not just meaningless but confusing as well. Is the reason why it is seen when run from perl but not when run directly in the CLI because cmd doesn't pass warnings, but perl does? Thanks !!

        in windows what would be the "normal" return code, 0 or 1?

        0 for success, like unix.

        then did echo %ERRORLEVEL% and the value returned was -1.

        That's weird. Error codes are unsigned in Win32. IF ERRORLEVEL even relies on that.

        @echo off program.exe if errorlevel 3 goto ERROR if errorlevel 1 goto WARNING rem 0 <= errorlevel < 1 echo Success goto END :WARNING rem 1 <= errorlevel < 3 echo Warning goto END :ERROR rem 3 <= errorlevel echo Error :END

        That's a very strange error message to return in the event of a negative return code.

        No, the message is correct for a negative code being returned from the function that implements system. The problem is that the function is returning negative when the child was successfully launched.

        In Win32, exit codes are unsigned 32 bit values. Perl treats it as a signed 32-bit value.

        DWORD status; ... GetExitCodeProcess(ProcessInformation.hProcess, &status); ret = (int)status;

        The second line is a bug. Sufficiently high exit codes will be converted to negative. Negatives are used to signal a problem launching the process.

        "Normal" return code seems to be zero. E.g., do a "dir" and then echo %ERRORLEVEL%. Now do "dir file_that_doesnt_exist" and echo %ERRORLEVEL% again. Now do " perl -e exit(-1)".
        echo %ERRORLEVEL% ... Is this the proper way to check this?

        Yes, I think so, but I'm no Windows expert...

        As to the negative return code, IIRC, I was able to reproduce the issue last time with a self-compiled perl-5.8.8 on a Win XP (32-bit) vmware image. Unfortunately, I don't have access to that image at the moment, and any attempts to reproduce the problem on the Windows box I currently have access to (XP x64 SP2, with ActiveState's Perl 5.8.8) have failed so far...

        Maybe I'll continue to play with this later. In case I should dig up something of interest, I'll report back.

Re: Can't spawn "cmd.exe":
by ikegami (Patriarch) on Mar 18, 2009 at 04:44 UTC

    In this case I'm not even asking it to start cmd.exe, but yet it's telling me that it can't spawn it.

    A command that requires the shell (such as one contains quotes) causes Perl to invoke the shell. This and related details is documented.

    "Can't spawn "cmd": Bad file descriptor at temp2.plx line 11."

    Are you checking $! to see if an error occurred? That would be incorrect.

    .plx? Do you get the error without whatever packager you are using?

      Hi, I'm not sure what you mean by packager. temp2.plx is just a perl script. As I mentioned above, I don't get the error when that program is run directly in the cmd CLI.
Re: Can't spawn "cmd.exe":
by ikegami (Patriarch) on Mar 18, 2009 at 15:21 UTC
    Independent of the problem you are reporting, your usage of system (as follows) is wrong.
    my $test = "/C \"C:\\...\\EXCEL.EXE\" C:\\test.xls"; system ("cmd",$test);
    You can either pass the whole command as one argument:
    my $test = "/C \"C:\\...\\EXCEL.EXE\" C:\\test.xls"; system ("cmd $test");
    or pass the arguments separately (note the lack of quotes):
    my @test= ("/C", "C:\\...\\EXCEL.EXE", "C:\\test.xls"); system ("cmd", @test);

    You are currently relying on a bug.

        system documents that the value of $test in system ("cmd",$test); will be passed as a single argument. If system behaved as documented, it would execute
        cmd "/C excel.exe text.xls"

        cmd does not accept that.

Re: Can't spawn "cmd.exe":
by Sandy (Curate) on Mar 18, 2009 at 14:50 UTC
    I'm not sure if this is relevant, but check the following node:

    Re: system command erroneously states 'can't spawn <executable>' from jimbojones

    The code (from 5.8.9) win32.c that might be causing the problem

    int Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp) { char **argv; char *str; int status; int flag = P_WAIT; int index = 0; if (sp <= mark) return -1; get_shell(); Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*); if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) { ++mark; flag = SvIVx(*mark); } while (++mark <= sp) { if (*mark && (str = SvPV_nolen(*mark))) argv[index++] = str; else argv[index++] = ""; } argv[index++] = 0; status = win32_spawnvp(flag, (const char*)(really ? SvPV_nolen(really) : argv[0]), (const char* const*)argv); if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) { /* possible shell-builtin, invoke with shell */ int sh_items; sh_items = w32_perlshell_items; while (--index >= 0) argv[index+sh_items] = argv[index]; while (--sh_items >= 0) argv[sh_items] = w32_perlshell_vec[sh_items]; status = win32_spawnvp(flag, (const char*)(really ? SvPV_nolen(really) : argv[0] +), (const char* const*)argv); } if (flag == P_NOWAIT) { PL_statusvalue = -1; /* >16bits hint for pp_system() */ } else { if (status < 0) { if (ckWARN(WARN_EXEC)) Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s +", argv[0], strerror(errno)); status = 255 * 256; } else status *= 256; PL_statusvalue = status; } Safefree(argv); return (status); }
    Notice that if the executable returns a negative error code, the assumption is that the spawn didn't work.

Re: Can't spawn "cmd.exe":
by BrowserUk (Patriarch) on Mar 18, 2009 at 11:57 UTC
    Thinking that this might be some weird sort of 32/64 bit issue, ...

    I can't reproduce your errors using AS1004 Perl 64-bit running under Vista 64-bit.

    #! /usr/bin/perl -slw use strict; print "About to try fail 1"; my $testfile = "test.exe"; my $test = "/C ${testfile} localhost root pwd"; system ("cmd", $test); print "About to try fail 2"; $test = "${testfile} localhost root pwd"; system ($test);

    In the following test.exe just displays its args:

    c:\test\test\test>test.pl About to try fail 1 0 : test.exe 1 : localhost 2 : root 3 : pwd About to try fail 2 0 : test.exe 1 : localhost 2 : root 3 : pwd

    In the first case Perl starts cmd.exe, which runs test.exe. In the second, perl runs test.exe directly. No error messages are produced by either.

    What version/build of Perl are you using?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Browser, It's 5.8.8. I think almut is on to something in his reply concerning negative return codes. Can you verify this by returning -1 from your test executable?

        Indeed I can:

        C:\test\test\test>test.pl About to try fail 1 0 : test.exe 1 : localhost 2 : root 3 : pwd Can't spawn "cmd": No error at C:\test\test\test\test.pl line 7. About to try fail 2 0 : test.exe 1 : localhost 2 : root 3 : pwd Can't spawn "test.exe localhost root pwd": No error at C:\test\test\te +st\test.pl line 11.

        Same result whether the return value is -1 or -100_000.

        The problem is with Perl's handling of Windows return codes. Trying to force fit a 32-bit signed int into an unsigned char doesn't go :)

        As for what constitutes a "valid windows return code"--a signed integer covers it. Long ago, there was a convention that positive return codes were 'informational', negative 'failures', with zero being unadorned success.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Can't spawn "cmd.exe":
by ikegami (Patriarch) on Mar 18, 2009 at 04:45 UTC

    In this case I'm not even asking it to start cmd.exe, but yet it's telling me that it can't spawn it.

    A command that requires the shell (such as one contains quotes) causes Perl to invoke the shell. This and related details is documented.

    "Can't spawn "cmd": Bad file descriptor at temp2.plx line 11."

    Are you checking $! to see if an error occurred? That would be incorrect.

    .plx? Do you get the error without whatever packager you are using?

Re: Can't spawn "cmd.exe":
by Anonymous Monk on Mar 18, 2009 at 04:00 UTC
    You don't show any error checking, where are you seeing these errors?
Re: Can't spawn "cmd.exe":
by Anonymous Monk on Jul 17, 2012 at 04:10 UTC
    For me returning -1 from the called script causes the problem. Returning other values i.e -2 solves the problem.
      I have a script where -1 is being returned from a lot of places which can not be changed. I have used "system" to call that script. Can anyone suggest how to get it working as I am getting the same can't spawn warning which is breaking my other logic. Thanks in advance
        no, not without details (code)