How to debug BATCH files

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
JimmyTheDos
Posts: 3
Joined: 20 May 2018 20:28

How to debug BATCH files

#1 Post by JimmyTheDos » 20 May 2018 21:34

Hi guys,

I have experience with VBA and excel, looking to expand my knowledge with BATCH.
  • Is there a way to "step into" (go line by line) of the code, (I can use "Pause" but this seems like not the best method.)
    Is there a way to run code without the repercussions (a way to prevent accidentally deleting all your files or something) or a way that is reversible.
    Is there a way to stop at a particular point and see the enviromental variables throughout the script (I guess this is the same as the "watches" window in excel, or "Set" in cmd?)
    Any other good advice?
Sorry if I am breaking any forum rules by a generic question!

Jimmy 8)

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: How to debug BATCH files

#2 Post by Ed Dyreen » 21 May 2018 12:24

JimmyTheDos wrote:
20 May 2018 21:34
Is there a way to "step into" (go line by line) of the code, (I can use "Pause" but this seems like not the best method.)
Often you want to debug only a particular function and often only if it is being called from a particular point, for that I programmed various debug functions. Functions could implement debug_ as follows

Code: Select all

:: --------------------------------------------------------------------------------------------------------------------------
:§myFunction_ ( null )
:: --------------------------------------------------------------------------------------------------------------------------
Rem ( %debugOn_% "!$trace!" )
::
( %debug_% "", "inside !$trace!(!%$trace%.p!)", /EQU )
::
( %forP_% '$rs,$r', '$rAs,"",""' )
::
:: (
	( %debug_% "valid()", /EQU )
	:: (

	:: )
	( %deq_% %necho$_% $debug.sub )

	( %debug_% "perform()", /EQU )
	:: (

	:: )
	( %deq_% %necho$_% $debug.sub )
:: )
( %debug_% "outside !$trace!()", /EQU, /PAUSE ) &exit /B !£e!
:: --------------------------------------------------------------------------------------------------------------------------
debugOn_ enables debugMode for the function specified as argument. debugOn_ can be used anywhere.
When debug is enabled for a function, all other debug commands become active
( %debug_% message, /PAUSE, /EQU ), ( %deq_% job ), ...
JimmyTheDos wrote:
20 May 2018 21:34
Is there a way to run code without the repercussions (a way to prevent accidentally deleting all your files or something) or a way that is reversible.
This happens to many at some point in time, a good way to protect your OS would be to do all the programming and testing from inside a virtual machine. VirtualPC is free but I prefer VMWare.
JimmyTheDos wrote:
20 May 2018 21:34
Is there a way to stop at a particular point and see the enviromental variables throughout the script (I guess this is the same as the "watches" window in excel, or "Set" in cmd?)
It's always nice to see exactly what arguments were passed to a function. My parser will print them on the console if debug is enabled for the function from where it is called. ( %forP_% 'name,value,default', 'and so on', .... ).
JimmyTheDos wrote:
20 May 2018 21:34
Any other good advice?
I cannot give you the code, I am too lazy, eh.. I mean it's too complex and depends on way too many factors to simply isolate this one functionality and hand it over to you. You could download and try out my library when my server is back online in a couple of weeks.

MarioZac
Posts: 38
Joined: 16 May 2018 00:12

Re: How to debug BATCH files

#3 Post by MarioZac » 21 May 2018 12:45

JimmyTheDos wrote:
20 May 2018 21:34
Is there a way to "step into" (go line by line) of the code
I'm not an expert batch coder, and therefore can give you only very basic advice. But may be this is exactly what you need. Once you figured out the entire batch skeleton, try using a combination of 2 methods to debug its sections:

- check and choose each command syntax at SS64 Commandline Reference (other sites like DOSTips and Stackoverflow add plenty of use case examples)
- once the syntax is more or less cleaned up, replace parts of syntax that manipulate your variables X and Y with this basic debug code:

Code: Select all

rem Goto :Next
echo !X! !Y!
rem (some code here)
: Next
rem (more code)
exit /b
This allows you to print resulting variable values to currently open Cmd Prompt window without running the rest of the code to avoid unintended damage to your system, and edit the snippet accordingly. Once you see vars X and Y work perfect, delete the above construct to enable your original code snippet, or simply bypass that section with Goto :Next function if the next one can be tested independently, and move on to the next snippet of your code to print and debug vars U and V ...

Its quite simple, and works amazingly well. However, when designing a relatively complex algorithm you need to see and plan a bigger code picture, and that's were the experts advice comes handy, since they have a large bag of tricks in their sleeves for almost every turn of your imagination, so long pages of your original code can be replaced by 2-3 expert lines, of which you might not understand a thing without verbiage. :D
Last edited by MarioZac on 22 May 2018 06:44, edited 2 times in total.

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: How to debug BATCH files

#4 Post by jfl » 21 May 2018 14:20

I've posted a powerful batch debugging library there:
https://github.com/JFLarvoire/SysToolsL ... ibrary.bat

You can find some high level documentation in the html file there:
https://github.com/JFLarvoire/SysToolsL ... iption.htm

There's also a very detailed low level documentation in the headers of Library.bat.

Example of use. This fact.bat script is instrumented using macros from Library.bat: (Which must be present in the path)

Code: Select all

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "SCRIPT=%~nx0"				&:# Script name
set ^"ARG0=%0^"					&:# Script invokation name
set ^"ARGS=%*^"					&:# Argument line

call library.bat source &:# Load the debug library
goto :Main

:#----------------------------------------------------------------------------#
:# Factorial routine

:Fact %1=argument %2=output variable (Optional, default=RESULT)
%FUNCTION% EnableExtensions EnableDelayedExpansion
set RETVAR=%2
if not defined RETVAR set RETVAR=RESULT
%UPVAR% %RETVAR%
set N=%1
if .%1.==.. set N=0
if .%N%.==.0. (
  set %RETVAR%=1
) else (
  set /A M=N-1
  call :Fact !M!
  set /A %RETVAR%=N*%RETVAR%
)
%RETURN%

:#----------------------------------------------------------------------------#
:# Help routine

:Help
echo.Usage: %SCRIPT% [OPTIONS] N
echo.
echo.Options:
echo.  -?	This help
echo.  -d	Enable debug mode
exit /b

:#----------------------------------------------------------------------------#
:# Main routine

:Main
set PARAM=
:next_arg
if not defined ARGS set "ARG=" & set ""ARG"=" & goto :Start
%POPARG%
if "!ARG!"=="-?" goto :Help
if "!ARG!"=="-d" %LCALL% :Debug.On & goto next_arg
set PARAM=!ARG!
goto :next_arg

:Start
call :Fact !PARAM!
echo !RESULT!
exit /b 0
If you run fact.bat "normally", it'll compute the factorial of a number. Ex:

Code: Select all

C:\JFL\Temp>fact 5
120

C:\JFL\Temp>
And if you invoke it in debug mode, it'll trace all instrumented functions:

Code: Select all

C:\JFL\Temp>fact 5 -d
call :Fact 5
  call :Fact 4
    call :Fact 3
      call :Fact 2
        call :Fact 1
          call :Fact 0
            return 0 & set "RESULT=1"
          return 0 & set "RESULT=1"
        return 0 & set "RESULT=2"
      return 0 & set "RESULT=6"
    return 0 & set "RESULT=24"
  return 0 & set "RESULT=120"
120

C:\JFL\Temp>

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: How to debug BATCH files

#5 Post by Ed Dyreen » 21 May 2018 15:00

@jfl,

I had a quick look at your batch library and read this line:

Code: Select all

:# FOREACHLINE macro. (Changes the delimiter to none to catch the whole lines.)
set FOREACHLINE=for /f "delims="
I tested it with:

Code: Select all

%FOREACHLINE% %%? in ( ";please preserve this line" ) do echo.?=%%?_
But it fails to produce any output because this line starts with an ; char, the default EndOfLine char. I change it to:

Code: Select all

set  ^"FOREACHLINE=for /F delims^^=^^ eol^^= %%r in"
And tested it with:

Code: Select all

%FOREACHLINE% ( ";please preserve this line" ) do echo.r=%%r_
And it works.

I am unsure whether you see this as a flaw or whether the behavior is intended, yet because the variable name FOREACHLINE suggests it should process each line I thought, nah-aah it doesn't.

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: How to debug BATCH files

#6 Post by jfl » 22 May 2018 03:52

You're right, this is a bug.
I'll fix that eventually as you suggest.
(Or better still, you can submit a pull request :-)

Post Reply