Batch Programming Snippets
Breakpoints and Debugging
If you write huge scripts and testing them for the first time, sometimes it would be nice to be able to debug them. There are some 3rd party applications arround, that can enable debugging of batch files but we want to use the “power of cmd.exe” to do that. When I write scripts, I define a custom command as a variable and place the variable all over my script. So changing that variable will enable/disable debugging.
Here is an example:
@ECHO OFF CLS SET MYPAUSE=@ECHO.^&@ECHO °°°°°°°°°°°BREAKPOINT°°°°°°°°°°° Press a key^&PAUSE^>NUL ::SET MYPAUSE=ECHO. ECHO. ECHO The script should stop between ECHO Here %MYPAUSE% ECHO and here.
With the above example the script will execute as follows
The script should stop between Here ░░░░░░░░░░░BREAKPOINT░░░░░░░░░░░ Press a key and here.
If you change to the following
::SET MYPAUSE=@ECHO.^&@ECHO °°°°°°°°°°°BREAKPOINT°°°°°°°°°°° Press a key^&PAUSE^>NUL SET MYPAUSE=ECHO.
the script will execute without a PAUSE
The script should stop between Here and here.
Voila - you can now debug your scripts a little bit better
Command extensions (check if enabled)
The cmd.exe supports the so called “Command Extensions”. They are enabled by default but can be enabled/disabled by setting a registry key or by command line. When cmd.exe starts it looks for the following registry keys to check if Command Extensions should be enabled or not.
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\EnableExtensions HKEY_CURRENT_USER\Software\Microsoft\Command Processor\EnableExtensions
It checks if a REG_DWORD exists there. If set to “0x1” it means Extensions are enabled and “0x0” means extensions are disabled.
If you rely on some features of cmd.exe in your batch files that only work if “Command Extensions” are enabled, you should check if they are enabled at the beginning of your script. But how? The answer is very simple and easy. You have to do 3 Steps.
- Execute an invalid command to set the errorlevel to 1
- Use SETLOCAL ENABLEEXTENSIONS to reset back the errorlevel to 0
- Check if the errorlevel is 0 (not the same as if %ERRORLEVEL%=0). If it is still 1 “Command Extensions” are not enabled.
So here is a small script to do the above job.
@ECHO OFF CLS ::Check if command extensions are enabled :: :: 1. Execute an invalid command to set the errorlevel to 1 :: A command that I think works good is the VERIFY command. :: It usually has only 1 Parameter so passing 2 it creates :: errorlevel 1 but does not complain. VERIFY FIRST SECOND>NUL :: 2. The variable %ERRORLEVEL% is now 1 if Command :: Extensions" are enabled. If we now try :: SETLOCAL ENABLEEXTENSIONS and Command extensions are on :: the variable %ERRORLEVEL% will be reset to 0 SETLOCAL ENABLEEXTENSIONS :: 3. If Command Extensions are not enabled, the SETLOCAL :: command will be executed and the ERRORLEVEL will be 1 :: (not the variable %ERRORLEVEL%). Keep in mind, that :: %ERRORLEVEL% is not the same as the ERRORLEVEL. IF NOT ERRORLEVEL 0 ( ECHO Command Extensions are off ) ELSE ( ECHO Command Extensions are on )
MYSLEEP (sleeping for some seconds)
Sometimes you need the opportunity to let your script sleep for some seconds. Most batch professionals know, that you can achieve this with a ping command to localhost. Here is an impressive way to implement a custom sleep command (MYSLEEP) into your scripts
We just join 3 commands together:
@echo [Sleeping 5 seconds - with the magic MYSLEEP]... ping -n 6 127.0.0.1 > NUL @echo done
into one line using the “^” character which means “Do a carriage return”. The “> NUL” means “Print the result to nowhere.”
@echo [Sleeping 5 seconds - with the magic MYSLEEP]...^&ping -n 6 127.0.0.1^>NUL^&@echo done
and store it into the variable MYSLEEP
SET MYSLEEP=@echo [Sleeping 5 seconds - with the magic MYSLEEP]...^&ping -n 6 127.0.0.1^>NUL^&@echo done
Now we can use “%MYSLEEP%” at anytime in our batch script to execute a sleep of ~5 seconds. Here is a sample script to demonstrate the usage:
@ECHO OFF CLS SET MYSLEEP=@echo [Sleeping 5 seconds - with the magic MYSLEEP]...^&ping -n 5 127.0.0.1^>NUL^&@echo done ECHO Hello World %MYSLEEP% ECHO Now it is 5 seconds later
format your date
This script will bring the computer date read from %DATE% into the correct format an also makes sure that single numbers get a leading 0. The script takes care about that there are only 4 possibilites than can be returned by %DATE%
xxx x/xx/xxxx delimiter on position 6 and 9 eg. Dec 1/12/2009 or Dez 12.1.2009 xxx xx/xx/xxxx delimiter on position 7 and 10 eg. Dec 12/12/2009 or Dez 12.12.2009 xxx xx/x/xxxx delimiter on position 7 and 9 eg. Dec 12/1/2009 or Dez 1.12.2009 xxx x/x/xxxx delimiter on position 6 and 8 eg. Dec 1/1/2009 or Dez 1.1.2009
The script stores the number(s) left of the first delimiter in the variable %DBB% and the number(s) left of the second delimiter in the variable %DAA%. Try it out!
@ECHO OFF CLS SETLOCAL rem set Delimiter eg. / or . SET TR=/ rem SET DATUM=Thu 1/1/2009 SET DATUM=%DATE% SET TRENNER=/ rem check format "xxx x/xx/xxxx" / on position 6 and 9 IF "%DATUM:~5,1%%DATUM:~8,1%"=="%TR%%TR%" (^SET DBB=0%DATUM:~4,1%&^SET DAA=%DATUM:~6,2%&^SET YEAR=%DATUM:~-4%&^GOTO CHECKEND) rem check format "xxx xx/xx/xxxx" / on position 7 and 10 IF "%DATUM:~6,1%%DATUM:~9,1%"=="%TR%%TR%" (^SET DBB=%DATUM:~4,2%&^SET DAA=%DATUM:~7,2%&^SET YEAR=%DATUM:~-4%&^GOTO CHECKEND) rem check format "xxx xx/x/xxxx" / on position 7 and 9 IF "%DATUM:~6,1%%DATUM:~8,1%"=="%TR%%TR%" (^SET DBB=%DATUM:~4,2%&^SET DAA=0%DATUM:~7,1%&^SET YEAR=%DATUM:~-4%&^GOTO CHECKEND) rem check format "xxx x/x/xxxx" / on position 6 and 8 IF "%DATUM:~5,1%%DATUM:~7,1%"=="%TR%%TR%" (^SET DBB=0%DATUM:~4,1%&^SET DAA=0%DATUM:~6,1%&^SET YEAR=%DATUM:~-4%&^GOTO CHECKEND) GOTO :CHECKEND :CHECKEND rem maybe you have to change the delimiter and the position of rem DBB and DAA when using german or other format echo %DBB%---%DAA%---YEAR%
format your date v2 (from internet)
See this page for more information. This version is much better than mine. It took me a while to understand but now I got it! :)
@echo off&SETLOCAL :: This will return date into environment vars :: Works on any NT/2K/XP machine independent of regional date settings :: 20 March 2002 FOR /f "tokens=1-4 delims=/-. " %%G IN ('date /t') DO (call :s_fixdate %%G %%H %%I %%J) goto :s_print_the_date :s_fixdate if "%1:~0,1%" GTR "9" shift FOR /f "skip=1 tokens=2-4 delims=(-)" %%G IN ('echo.^|date') DO ( set %%G=%1&set %%H=%2&set %%I=%3) goto :eof :s_print_the_date echo Month:[%mm%] Day:[%dd%] Year:[%yy%] SET FileDate=%yy%_%mm%_%dd% ENDLOCAL&SET mm=%mm%&SET dd=%dd%&SET yy=%yy% SET FileDate=%yy%_%mm%_%dd%
The above works by taking advantage of a quirk in the date command first noticed by Michael Jerkovic - the DATE command will display something like:
The current date is: Fri 14/04/2000 Enter the new date: (**dd-mm-yy**)
The useful bit there is the (dd-mm-yy), on a machine with different regional settings it may appear as (mm-dd-yy)
The first FOR command returns the 3 numeric parts of the date e.g. 14 04 2000 The second FOR command returns the 3 text descriptions e.g. dd mm yy Then the line set G=%1&set H=%2&set %%I=%3 creates the 3 variables and sets them = numeric values
Effectively: set dd=14&set mm=04&set yy=2000 On a machine with different regional settings this might become: set mm=04&set dd=14&set yy=2000
Note the reason this works with any regional setting is that the DATE string (dd-mm-yy) always displays with `-` as it's date separator.