2

You can use | more to step through a .bat file, and you can redirect the output to a file for later analysis, but often the errors are not that obvious. You don't get a handy "ERROR:" prefix and the errors dos commands can print are pretty varied. This makes exhaustively searching for any possible errors quite difficult.

So I wondered if there was a way to make a batch file automatically pause when an error occurs?

Mark
  • 3,609
  • 1
  • 22
  • 33
Mr. Boy
  • 60,845
  • 93
  • 320
  • 589
  • If you are referring to syntax errors then no, there is no handy debugger. – foxidrive Nov 22 '13 at 15:26
  • 1
    @foxidrive - I can't pause after error, but I figured out a way to detect if there was an error (with a possibility of some false positives). See my answer. – dbenham Nov 22 '13 at 17:03

3 Answers3

2

Afaik, there is no generic way, especially not when combined with |more. But many commands return an errorlevel, which you can read and act upon.

Here is a list of some errorlevels returned by some commands. For instance find returns 1 if no results were found or a higher value if the search was aborted for another reason.

So you could write this:

find ...parameters...
if ERRORLEVEL 1 (
  echo 'No files found'
  pause
)

The if ERRORLEVEL X syntax matches any errorlevel that is >= X. That is convenient, because many programs return 0 or specific low values to indicate success and higher values to indicate errors, as will most of the commands in the list, so this syntaxt allows you to capture all those error codes in a single condition.

You'll have to read the documentation of the command or the programs you start in your batch file to see if they return errorlevels and if so, what each value means.

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
1

Batch does not have any exception handling. If you want to reliably detect errors, then your script must explicitly check for an error condition after every command. But that can be a tedious process, and not very practical for existing scripts.

I can't think of a simple way to pause after every error, but you can detect if there was likely an error at some point during the execution. You could write another batch script to call your script, and redirect stderr to a file. Then check the size of the err file when finished - if greater than 0, then there was probably an error.

@echo off
call yourScript.bat 2>err.log
for %%F in (err.log) do if %%~zF neq 0 echo There probably was an error.

There are two problems with the above.

1) A few commands write informational text to stderr that are not true errors. If this is a problem in your case, then you cannot use this method.

2) The errors are not displayed to the screen, and the errors captured in the file are missing the context of the rest of the output. You can solve this problem if you download a tee program and swap stderr with stdout. One free source for obtaining tee is Gnu CoreUtils for Windows.

@echo off
call test2.bat 3>&2 2>&1 1>&3|tee err.log
for %%F in (err.log) do if %%~zF neq 0 echo Warning: There probably was an error

Unfortunately, this cannot work if you want to capture both stdout and stderr in the same log file. You would be back with the problem of differentiating error text from non-error text.

dbenham
  • 127,446
  • 28
  • 251
  • 390
1

There is another solution that is also based on identifying the error messages sent to STDERR, so it have the same problems described by dbenham in his answer, but it doesn't require to modify the existent Batch files in any way.

The solution uses this trick to show normal lines preceded by a number in one color and error lines preceded by a different color one. This way you may differentiate error lines in the screen, although the colors are not stored in a text file if the output is redirected.

( theBatchFile | findstr /N /A:2A "^" ) 2>&1 1>&3 | findstr /N /A:4E "^"

The problem with this method is that normal and error lines does not appear in its original order, but in separated parts. This happen because each block of lines is processed by different findstr commands, but this solution may be enough in certain cases.

EDIT: New method added

I made several tests on this solution. Stdout and Stderr lines are not grouped as I thougth at first. Its order depends on the initial delay to start the second findstr, that causes that initial Stderr lines be delayed, and the fact that both output may be mixed in the screen. If a Batch file show a majority of Stdout lines and a few Stderr lines now and then, then the output preserve the original order.

I wrote a small Batch-JScript hybrid script called ShowErrors.bat that allows to differentiate Stderr lines in any way you wish:

@if (@CodeSection == @Batch) @then

@echo off

if "%~1" equ "" (
   echo ShowErrors.bat command parameters ...
   echo/
   echo Execute the command and differentiate lines sent to Stderr
   goto :EOF
)

%* 2>&1 1>&3 | CScript //nologo //E:JScript "%~F0"

goto :EOF

@end

while ( ! WScript.Stdin.AtEndOfStream ) {
   WScript.Stdout.WriteLine("======================================================");
   WScript.Stdout.WriteLine("ERROR: "+WScript.Stdin.ReadLine());
}

This is a small Batch file as example of mixed Stdout/Stderr output program:

@echo off
rem Initial delay
ping -n 2 localhost > NUL
for /L %%i in (1,1,4) do echo Starting lines to Stdout
for %%a in ("2 4" "3 6" "4 8") do (
   for /F "tokens=1,2" %%i in (%%a) do (
      echo %%i lines to Stderr: >&2
      for /L %%x in (1,1,%%i) do echo Line %%x to Stderr >&2
      ping -n 1 localhost > NUL
      echo %%j lines to Stdout:
      ping -n 1 localhost > NUL
      for /L %%x in (1,1,%%j) do echo Line %%x to Stdout
   )
)

This is the output when it is executed in the normal way: test:

Starting lines to Stdout
Starting lines to Stdout
Starting lines to Stdout
Starting lines to Stdout
2 lines to Stderr:
Line 1 to Stderr
Line 2 to Stderr
4 lines to Stdout:
Line 1 to Stdout
Line 2 to Stdout
Line 3 to Stdout
Line 4 to Stdout
3 lines to Stderr:
Line 1 to Stderr
Line 2 to Stderr
Line 3 to Stderr
6 lines to Stdout:
Line 1 to Stdout
Line 2 to Stdout
Line 3 to Stdout
Line 4 to Stdout
Line 5 to Stdout
Line 6 to Stdout
4 lines to Stderr:
Line 1 to Stderr
Line 2 to Stderr
Line 3 to Stderr
Line 4 to Stderr
8 lines to Stdout:
Line 1 to Stdout
Line 2 to Stdout
Line 3 to Stdout
Line 4 to Stdout
Line 5 to Stdout
Line 6 to Stdout
Line 7 to Stdout
Line 8 to Stdout

This is the output when it is executed via ShowErrors test:

Starting lines to Stdout
Starting lines to Stdout
Starting lines to Stdout
Starting lines to Stdout
======================================================
ERROR: 2 lines to Stderr:
======================================================
ERROR: Line 1 to Stderr
======================================================
ERROR: Line 2 to Stderr
4 lines to Stdout:
Line 1 to Stdout
Line 2 to Stdout
Line 3 to Stdout
Line 4 to Stdout
======================================================
ERROR: 3 lines to Stderr:
======================================================
ERROR: Line 1 to Stderr
======================================================
ERROR: Line 2 to Stderr
======================================================
ERROR: Line 3 to Stderr
6 lines to Stdout:
Line 1 to Stdout
Line 2 to Stdout
Line 3 to Stdout
Line 4 to Stdout
Line 5 to Stdout
Line 6 to Stdout
======================================================
ERROR: 4 lines to Stderr:
======================================================
ERROR: Line 1 to Stderr
======================================================
ERROR: Line 2 to Stderr
======================================================
ERROR: Line 3 to Stderr
======================================================
ERROR: Line 4 to Stderr
8 lines to Stdout:
Line 1 to Stdout
Line 2 to Stdout
Line 3 to Stdout
Line 4 to Stdout
Line 5 to Stdout
Line 6 to Stdout
Line 7 to Stdout
Line 8 to Stdout
Community
  • 1
  • 1
Aacini
  • 65,180
  • 12
  • 72
  • 108