2

I'm working on a problem in a codebase where a perl script calls a batch script and does stuff based on the exit code. In some cases, although statements like exit /b 1 are executed and the batch script exits, the exitcode is seen as 0 by the perl script. I've narrowed it down to the following example.

Here's a minimal version of the perl script:

#!/usr/bin/perl
print "calling bat with @ARGV\n";
qx(batscript.bat @ARGV);
my $exitcode = $? >> 8;
print "return code from bat is $exitcode \n";

And here's a minimal version of the batch script:

@echo OFF
setlocal enableextensions
if "%~1" == "err" (
    echo "non-zero code requested"
    exit /b 1
    echo hello
)
endlocal

This is what I get:

c:\tmp>plscript.pl
calling bat with
return code from bat is 0

c:\tmp>plscript.pl err
calling bat with err
return code from bat is 0

If I remove that echo hello line from the batch script, it works properly:

c:\tmp>plscript.pl
calling bat with
return code from bat is 0

c:\tmp>plscript.pl err
calling bat with err
return code from bat is 1

Is this a bug in how batch runs and processes statements in blocks? It would be preferable not to have to refactor the batch script since it's quite big and has many exit /b statements.

Lurch
  • 63
  • 6
  • 1
    I would assume you are getting an error code which idicates that the command really run when you execute batscript.bat, i.e. `cmd.exe /C batscript.bat`, executed successfully. I would also ask that you try `Exit 1` rather than `Exit /B 1` – Compo Nov 08 '22 at 16:18
  • Nothing to do with Perl. You get the exact same behaviour from `cmd /c batscript.bat err` from the command instead of from Perl. – ikegami Nov 08 '22 at 16:35
  • @Compo Yes, `exit 1` works but I was hoping for a different solution, as the batch script can also be used directly or via other scripts from the command-line and I don't want to close the cmd.exe window. – Lurch Nov 08 '22 at 16:57
  • 1
    `Exit /B 1` returms `error code 1` to the batch file's 'parent' cmd.exe process or calling batch file. In this case, as it was started with `cmd.exe /C`, and has no further commands to run, simply closes cmd.exe extinguishing that error code. `Exit 1` closes the batch file's 'parent' cmd.exe process, with an error code of `1`, which is what you were trying to achieve. If you need something different then you are going to have to submit much more information. – Compo Nov 08 '22 at 17:11
  • This was just a stripped-down example to illustrate the problem I'm having with the exit code of a batch script. The `err` parameter was just to trigger the error for this example. In reality, the batch script can also be called by users directly from the command-line, that's why I didn't want to use `exit 1` which closes the cmd.exe window. – Lurch Nov 08 '22 at 17:46
  • 1
    So have `perl` set an environment variable like `calledfromperl` and interpret that as a flag to determine the `exit` strategy. – Magoo Nov 08 '22 at 18:34
  • 1
    What happens when you replace `qx(batscript.bat @ARGV);` by `qx(cmd /D /C call batscript.bat @ARGV);`? – aschipfl Nov 08 '22 at 22:27
  • 2
    **1.** The **Table 4** of [this answer](https://stackoverflow.com/a/34987886/778560) specify that `EXIT /B number` sets the errorlevel for the `CALLing Subroutine` Batch file, whereas `EXIT number` ends cmd.exe and sets its (of cmd.exe) returning errorlevel. **2.** If you want that the Batch script executes an `exit 1` when it was called by perl, and an `exit /B 1` if it was called via command-line or another script, then you can include both forms and select the right one via an `IF` command that uses the `%CMDCMDLINE%` variable to identify the method used to start it. – Aacini Nov 09 '22 at 03:58
  • @Magoo Yes, that's what I thought I'd end up doing, but the suggestion from aschipfl did the trick. – Lurch Nov 09 '22 at 10:32

1 Answers1

1

Based on a suggestion from aschipfl, I eventually settled on changing the way the batch script is called, by using CALL. I like this solution because I don't have to modify the batch script (which can be called either by the perl script or by users directly from a cmd.exe window).

So basically in the perl script I changed the 3rd line from:

qx(batscript.bat @ARGV);

to:

qx(call batscript.bat @ARGV);
Lurch
  • 63
  • 6