|
I have some peculiar ways of doing things in my batch files. I have collected examples of my most frequently used oddball techniques here. If you know about them, you just might be able to follow what I do in the rest of my batch file examples.
| Downloading Example Batch Files |
In an effort to beautify my web site, an unwanted side effect was introduced. Using 'cut and paste' to extract the example procedures from the displayed text is not as useful as I would have hoped (at least not using the browser I have). The pasted text wanders all over the page, with lots of extra spaces prefixing most lines. In addition, some of my examples use special ASCII characters that Windows does not like to show. Displayable substitutions are made in the text to counter this effect, but it's time consuming to correct the procedures once they've been pasted into an editor. So, links to a plain text version of each of the example batch files are provided. Access this copy by clicking on the batch file's name in the example. Using a 'right-click' in the most commonly used browsers allows them to be saved directly, without the intermediate step of pasting in an editor. Use cut and paste of the displayed text version, if need be. The downloaded file may not display correctly, but it will have all of the necessary bits and pieces intact.
| Toggling ECHO ON/OFF for Debugging |
The least intrusive way to disable an ECHO OFF command in a batchfile is to put a simple environment variable between the words ECHO and OFF. This is useful when a routine is first being checked out or modified so that the operation can be traced to find errors. When the variable is SET equal to the string ON (not case sensitive) it will restore command echoing while the procedure runs. Issuing 'SET VAR=' restores the normal operation of the ECHO OFF command.In use, you might do something like this ...
@ECHO %DBG% OFFBy simply typing
ECHO The rest of the batch file ..SET DBG=ONat the C:\> prompt, the initial ECHO OFF will be defeated. To clear the debug mode, simply typeSET DBG=I have added a debugging variable to all of my batch files that has the first letter of the procedure's name at the end of the 'DBG' variable name (ECHO %DBGA% OFF, for example). This naming convention goes a long way to assuring that only the batch file being debugged at the moment will sound off to the screen. Other routines that are called from the procedure being tested remain silent because their variable is not 'SET' to 'ON'. The simple naming convention also makes it easy to remember how to turn debugging on and off.
| Setting Breakpoints |
An extension to the previous idea leads to a simple way to include breakpoints in batch files. That is to use environment variables SET equal to the string PAUSE when a breakpoint is desired and SET equal to an empty string otherwise. For example,@ECHO %DBGB% OFFTo pause the batch file at the breakpoint type
ECHO Start ...
.
.
%BRKPT%
ECHO Continuing ...
SET BRKPT=PAUSEat the command prompt. To clear it typeSET BRKPT=Another use of this technique is to display a variable's value somewhere in the procedure while testing. For example, some of my later routines contain a variable named, For example. I use it to display the final result of utility procedures because in normally use the intention is to store the result into a variable for use elsewhere, but not display it. This can easily be coupled with a breakpoint in a FOR statement, something like ...for %%v in (%For Example%) do %%v Var: %Var% The SET statement to display an intermediate result is something like ...set for example=echo Or, to add a breakpoint as well ...set for example=echo pause This approach adds a lot of versitility with just a little overhead. I like the fact that I only need to set the condition once for an extended debugging session without having to edit the procedure or continually add a switch string to the command line.
| Minimalist Error Handlers and Mini Subroutines |
DOS has many peculiarities. Some are useless bits of trivia, while others turn out to be surprisingly useful. One of the peculiarities that I have made use of is that of the lowly colon (:). I have found that it works perfectly well as a delimiter in some situations and not in others. For example, a GOTO works just fine with a colon between the 'GOTO' part and the label part. This may seem like a real "so what", but it's a very crutial part of one of my favorite little tricks; using a FOR command to form a one line error handler.For example, the following line will explain that a batch file is missing an important command line input argument and then branch to the end of the routine.
Another way to use this little "minisubroutine" is in collecting input arguments into a single environment variable or to CALL and then DELete a secondary batch file (one created for a single use within the calling routine). They might look like this ...for %%v in (echo goto:End) do %%v Syntax: %0 InputArgument or:Loop if not [%1]==[] for %%v in (set shift goto:Loop) do %%v Var=%Var% %1 for %%v in (call del) do %%v {temp}.bat
| Peculiar Redirection |
If I'm known for anything within the circle of diehard batch programmers, it is for my placement of redirections in "places God never intended." Personally, I don't think God cares where I put them. But, more to the point, neither does DOS. (Please note that the 'DOS' in Windows NT is NOT DOS. It doesn't smell like a duck or quack like a duck or taste like a duck.) DOS (but not WinNT) handles redirections just as well at the beginning as at the end of a line. For example, the following three lines perform identically, though they look different.echo This is a test. > {test} echo> {test} This is a test. > {test} echo This is a test. So, if they act the same, why do I tend to use the latter, over the former? Good question!I like the way it looks.
For example, when I redirect several commands in a row into a file, I find it easier to read when all the file name parts and command parts line up in neat columns.
For example, I find this easier to follow
> {temp} echo This is the first line. >>{temp} echo This is the second >>{temp} echo and this is the last one. than thisecho This is the first line.> {temp} echo This is the second>>{temp} echo and this is the last one.>>{temp} When I want to change a redirection, I can scan the left margin for lines that are being redirected, -and be reasonably confident I have seen every line. Or when I want to trace the logic, I think it's easier to find the command part of the line when they're lined up this way.Whether you agree with me or not, at least now you know what I'm doing when you see the batch file listings.
| Useless(?) Redirections |
Some of my procedures appear to have some bizare redirections in them. For example, why would a sane person redirect the output of a 'SET Var=' instruction into a file? There is no output from such a command.Aha, you've discovered my secret! I'm not sane! Though, I prefer to think of it as being 'crazy as a fox' (but then again, maybe ...).
Believe it or not, there is a rational reason. I use this approach to make sure a file is empty without adding a statement to the procedure. One use is before a FOR statement used to create a list of things in a file. Because of the way a FOR statement works, a simple redirection cannot create a list. The resulting file will only contain the last thing output from the FOR. However, a list is created when the output is appended to a file. So, the bogus redirection empties the file in anticipation of the list creation to follow. The one command does double duty.
Another time this is useful is to create a zero byte flag file. That is, a file whose mere existence flags a condition, say an unfinished process or an error condition. The 'IF EXIST' test permits branching based on its presence or absence.
| Undefined Environment Variables as Comments |
Okay, while we're on the subject of useless definitions, lets talk about the use of environment variables that don't exist. I have started to use them in the past six months or so to provide 'inline' comments. The idea is to just insert the comment anywhere you want on the line, enclosed in percent signs. Further, if the first character after the percent is a space, these 'variables' cannot be created.This works because the command processor omits all of the text between the percent signs at run time, since no substitute string exists in the current definition of the environment. Thus, the text becomes a comment for maintenance, having no impact on the operation of the procedure.
For example, in a recent discussion in the alt.msdos.batch newsgroup someone wanted to create a QBasic like IF - Then - Else construct. I suggested something like ...
if not [%1]==[String] %Then% goto Else echo %1 equals String % This is where the If True clause goes % goto EndIf :Else echo %1 not equal to String % This is the ELSE clause % :Endif Some wag pointed out that by defining an environment variable 'THEN' equal to 'FORMAT C: /something', this construction would make someone very unhappy. He's right, but the solution is to simply add a space after the leading percent sign (and for esthetics before the trailing one, as well), as I did in the other two comments in the example. Used in this way, the variable just cannot be created (at least not by reasonable means) and nothing unexpected can happen.There is a little overhead in using such comments, as the command processor must parse the extra characters on the statement line, but it is not much. I think it is well worth the cost, adding significantly to the ability to document the procedures. Of course, I haven't gone through all of mine yet to add appropriate comments, though I know they need them. That's another issue.
| Recursion and the Double Colon (::) |
Recursion means a function calls itself. It is a very effective technique in a batch file. It is especially valuable in collecting data from DOS utilities for use in the running batch procedure. Nearly all of my procedures use it. If you see a %0 in a statement, it almost always indicates recursion is being used. However, there is an obvious need to keep the routine from calling itself over and over again. That's where the double colon comes in.A line beginning with a pair of colons is not acted on by DOS. It's treated, instead, as an unusable label. Everything after the second colon is ignored. Thus, it is commonly used to enter comments into batch procedures. It is processed much faster than the REM statement provided as the 'documented' comment specifier.
A fellow netizen, John Savage, introduced me to the double colon's usefulness in flow control in a recursive batch file. In particular, any line can be converted to a comment line by inserting a pair of colons at the start of the line, using a command line replaceable argument.
| Fixes, Changes and Disclaimers |
I try to test every procedure and technique I post here, but like everyone I sometimes make a mistake. If you find what you believe is an error or problem, please drop me a line at my current address. I will definitely look into the issue, but cannot take responsibility for any problems my error might cause you.I am adding to the content and reserve the right to 'tweek' the routines. You may want to check back on occasion to see if there have been any changes made. Check here first for a summary of the fixes and updates.
Changes, Updates and problems that have been fixed:
Action Affected Page Date Logic bug Testdrv 11 Nov 96 New material Counting 1 Mar 97 Bug fix Random 18 Mar 97 LEFT.BAT revised CntLoop 18 Mar 97 Bug fixes to POKER.BAT & CARDS.BAT DEAL 25 Mar 97 Win 95 fix Once 26 Aug 97 Reworked, simplified and extended Alarm 25 Nov 97 Win NT caveat for INPUT.BAT added Input 25 Nov 97 New list processing article. DoList 13 Apr 98 Added link to new "Parsing Date String" article TimeDate 15 Apr 98 Added link to ANSI.BAT article TimeDate 15 Apr 98 Corrected a broken link to PC Magazine article. Counting 16 Apr 98 Tweak FULL and FILL procedures. Wallpaper 21 April 98 Fix some broken links Resum‚ 10 Jun 98 New material Real Math 20 Jul 98 I've MOVED! Everything 29 Jul 98 New content Input95 13 Oct 98 ANSIDEMO.BAT bug fix ANSI 19 Oct 98 New content IncrDecr 26 Dec 98 More edits and additions Genotes 29 Dec 98 Add Win NT reference to Time and Date article TimeDate 27 Apr 99 Extend UniPDate article (now has time, too) PDate 30 Apr 99 Added Bookmark Links Bookmarks 11 Jun 99 New content Datesift 13 Aug 99 Revised and Updated Testdrv 16 Aug 99 Revised and Updated Random 18 Sep 99 Revised and Updated Deal 18 Sep 99 Revised and Updated Games 18 Sep 99 Win NT time and date, updated NTDate 14 May 2001 Cosmetic Update Everything 31 Jan 2003 Remove Broken Links Bookmarks Feb 2003 Make Win 2000 compatible Compare Feb 2003 Added some WSH VBScript examples WSHIndex Jul 2004 Added MS-DOS console example to WSH page WSHIndex Jul 2006