Internal and Intrinsic Commands

CALL
is much like calls in high level languages. It causes the name of the calling batch file and the location in the file to be saved (by COMMAND.COM) so that execution can be resumed at the next line in the file, when the called batch file terminates. Since each CALL consumes some memory until it is cleared by the return of the called program, there is a finite limit to the number of CALLs that can be nested. I don't know what this limit is, or any other details of how the call in managed internally by COMMAND.COM. You can demonstrate the existence of the limit with this program


 @echo off
 call %0
 :end
which will just sit there with the cursor blinking for quite a while before issuing an error message and terminating (the following is a screen dump of the above).

 H:\>test
Insufficient memory
 H:\>
CALL lets you invoke a batch file from a batch file without loosing your place in the first one. The two batch files may be different files, or the same file. When they are the same, the effect is that of recursion. CALL causes COMMAND.COM to save the name and file pointer for the current file before invoking the second one and to reenter the original file at the location indicated by the file pointer on its termination. CALL can also be used to invoke executables, though COMMAND.COM doesn't seem to do anything different when you do. However, there is a certain flexibility in using CALL to invoke executables: you can later replace the .EXE file with a same named .BAT file to change the action. It is also safer to use CALL when you don't know for sure that the program you have been told just the name of is in fact a .COM or .EXE, rather than . .BAT file. CALL also is useful in FOR loops both in batch files and from the command line to prevent the loop from terminating prematurely when the action is a batch file (FOR %a in (foo.bat bar.bat baz.bat) do %a will execute only FOO, but FOR %a in (foo.bat bar.bat baz.bat) do call %a will execute all three).


CD changes the default directory on either the default or given drive. It is important to keep in mind that when changing the directory on a non-default drive the default drive itself is not changed:


 c:
 cd d:\foo
leaves you in the C: drive, but changes the default directory on the D: drive to \FOO. This is sometimes useful, but it should be kept in mind that under Windows, the default directory on any drive is subject to being changed by another program while the batch file is running - it is a very good idea to assume nothing about the default directory though not all of the examples in this book actually take that recommended precaution. Not even the default directory on the default drive for the window in which the batch file is running can be assumed to be stable.

When running under Windows it is seldom necessary to remember what the previous directory was when changing it, but under plain DOS it often is. There are several utilities available that push and pop directories - these utilities are well worth using, but since this book is about what can be done using just what comes with MSDOS 6.22 they are ignored here. For most purposes only the default directory on one drive needs to be saved and restored:


 @echo off
 dir
 dir | find "Directory" > }{.bat
 echo set dir=%%2> director.bat
 call }{
 del }{.bat
 del director.bat
 cd \
 dir
 cd %dir%
 dir
 :end

illustrates that - note that it assumes that the default directory is writable and stable. The usual way of handling unstable directories is by specifying the directory, but that doesn't work here because there isn't any reasonable way to include the directory in }{.BAT. The work around I use is to map a drive to a directory and do my DOS work there - the special drive must not be used for any Windows programs, though it is safe to let many Windows programs work with files there. It is especially important to do something like this if the working directory is on the same drive as Windows.


DIR generates a list of files and/or subdirectories in the current or given directory. It has a number of switches that modify its action and the output is frequently redirected into files, or through filters to modify the output even more. The HELP on DIR is unusually through and accurate, and is misleading hardly at all. Since I really can't say it any better than MS did, see the HELP entry and/or the built in syntax information (the /? switch). DIR is an internal command and has no errorlevel return. One extension to its functionality that was omitted from the command but is highly useful is the ability to display listings for multiple patterns in the same command:


 dir *.exe *.com *.bat *.pif
doesn't work, but would certainly be handy for listing all the programs in a directory. Needless to say, I have written a batch file that does this: DIRX.BAT.

Again, please see HELP DIR or DIR /? for the syntax (there just isn't much way to rewrite the material and I don't want to just copy existing material for this book. If you insist, a dump of the /? stuff is in a separate file here (I'll probably wind up doing that for most of the commands if MS doesn't get in my case about it). The file was generated with the command


 dir /? > dirhlp.txt


ECHO (on, off, or text)
is really two commands: one to control the ECHO status (whether the command lines in the file will be displayed, or just the messages they generate) using the ON and OFF arguments, and one to display text on the console (through STDOUT (STandarD OUTput)). The fact that the ECHO status has no effect on ECHOed text points out that difference. Most batch files begin with @ECHO OFF to suppress display off all the commands in the file (the '@' symbol suppresses echoing of the line it begins, so not even the ECHO OFF command is displayed). If a batch file is always invoked or called by another, only the first one need have the @ECHO OFF command, which will remain in force as long as COMMAND.COM remains in batch mode. Note that this does not affect secondary command processors:


 @if "%1" == "" echo off
 if  "%1" == "" command /c%0 foo
 :end

ECHO <text> seems to have been provided as a means of issuing messages to the user, but there are other uses. The not well documented syntax ECHO. (note the '.' at the end of the command) ECHOs a blank line. This is quite useful, when piped to certain commands, for supplying the <Enter> required to terminate the command:


 @echo off
 echo. | date
 echo. | time
 :end

ECHO is also used in a similar way with 'y' or 'n' to provide an automatic response to a command requiring a Y/N response. The most common use of this is, perhaps, to automatically delete the garbage in the TEMP directory during AUTOEXEC.BAT:


 echo y | del c:\temp\*.*
But beware - always specify the exact drive and directory in full - never do it this way

 set TEMP=c:\temp
 echo y | del %temp%\*.*
because this depends on the variable actually getting set - and accidents do happen. Failure of the set command causes the DEL command to delete all the files in the current directory, which is likely to be the root of the boot drive.

ECHO, without any arguments, simply displays the echo status: either ON or OFF.

There are some cases where what appears to be correct syntax doesn't cause error messages but doesn't work either. Most of these involve conditional redirection:


 for %%a in (foo) do echo %%a > baz
 if not !%1 == ! echo foo > bar

don't work, at least not reliably. It is far safer to put the redirected echo command somewhere else and get at it with a CALL or to jump over the echo with an inverted conditional GOTO:


 if !%1 == !}{ goto %2
 for %%a in (foo) do call %0 }{ report %%a
 if !%1 == ! goto cont
 echo foo > bar
 :cont
 goto end
 :report
 echo %3 > baz
 :end

The FOR x in (set) do
command has many uses. It appears that the original intent appears to be to return file names in a list or matching a pattern one at a time, and it is still very useful for that sort of work:


 @echo off
 for %%a in (*.bat) do if not exist .\bak\%%a copy %%a .\bak
 :end
makes sure that there is a backup copy of each of the batch files in the default directory, but copies only the ones that don't already have backups. It doesn't check to see if they are the same, but the backups may well be intended to be the previous versions. Note that the variable is a single letter preceded by double '%' signs. One of these is stripped off during command processing, so the real name is "%a", which is what you use when using this syntax from the command line. (It is not essential that the variable name use a letter, but numbers are forbidden and the convention is to use letters that mean something or are in alphabetic order (for multiple uses of FOR in the same file). FOR also has other uses, for example, to process a list of items:

 for %%a in (*.bat *.exe, *.com) do if not exist .\bak%%a copy %%a .\bak
does what the first example does, except for all three of those extensions.

The list (set) need not have anything to do with files, as the following three digit counter illustrates:


 @echo off
 if "%1" == "}{" goto %2
 set target=%1
 command /e:1024 /c%0 }{ pass0
 goto end
 :pass0
 for %%a in (0 1 2 3 4 5 6 7 8 9) do call %0 }{ pass2 %%a
 goto end
 :pass2
 for %%b in (0 1 2 3 4 5 6 7 8 9) do call %0 }{ pass3 %3 %%b
 goto end
 :pass3
 for %%c in (0 1 2 3 4 5 6 7 8 9) do call %0 }{ pass4 %3 %4 %%c
 goto end
 :pass4
 set count=
 :loop1
 if "%3" == "" goto done
 REM - uncomment the following line to enable leading zero suppression
 REM if "%3" == "0" if "%count%" == "" goto x1
 set count=%count%%3
 :x1
 shift
 goto loop1
 :done
 if "%count%" == "" goto end
 :usercode
 REM user specific code to use the number goes here
 :userend
 if "%target%" == "%count%" exit
 :end
This was written in response to a question about how to rename files with consecutive numbers. It accepts a target number beyond which it will not count as an argument, and the user code would use the file name passed as the second argument as the file to rename. The user code would generate the name and test for the existence of a file with that name, continue to loop as long as there was one, and exit after finding the first unused number. I omitted that code since it was specific to one particular user. Note that if you are using leading zeros (the default) the target argument must be exactly three digits long - use leading zeros for one and two digit numbers.

A more usable form of the above (called RENnnn.BAT) takes five arguments: the name of the file to rename, and (optionally) the prefix to put in front of the number, the extension to apply, the limiting number and a path to apply to the given filename. If no limit is given, the default is 999. Obviously, if any of the later options are used, the earlier ones must also be supplied - ',' can be used to indicate that an argument is a null.


 @echo off
 if "%1" == "}{" goto %2
 set target=%999
 set fname=%1
 set prefix=%3
 set ext=%4
 set dir=%2
 if !%5==! goto begin
 set fname=%dir%\%fname%
 command /e:1024 /c%0 }{ pass0
 goto endcount
 :pass0
 for %%a in (0 1 2 3 4 5 6 7 8 9) do call %0 }{ pass2 %%a
 goto endcount
 :pass2
 for %%b in (0 1 2 3 4 5 6 7 8 9) do call %0 }{ pass3 %3 %%b
 goto endcount
 :pass3
 for %%c in (0 1 2 3 4 5 6 7 8 9) do call %0 }{ pass4 %3 %4 %%c
 goto endcount
 :pass4
 set count=
 :loop1
 if "%3" == "" goto done
 REM - uncomment the following line to enable leading zero suppression
 REM if "%3" == "0" if "%count%" == "" goto x1
 set count=%count%%3
 :x1
 shift
 goto loop1
 :done
 if "%count%" == "" goto endcount
 :usercode
 if exist %dir%\%prefix%%count%.%ext% goto userend
 if not exist %fname% exit
 echo Copying %fname% to %dir%\%prefix%%count%.%ext%
 copy %fname% %dir%\%prefix%%count%.%ext%
 echo Deleting %fname%
 del %fname%
 exit
 :userend
 if "%target%" == "%count%" exit
 :endcount

Note that the passed prefix can contain a path and or a base (relative to the given directory) for the new name itself. This version does nothing if the target file already exists or if the given file does not exist.

Note that all these numerical renaming programs start with 000 as the first number. the code can be modified to start at any number by creating an environment variable containing the starting number (with leading zeros if you are using them) and modifying the usercode section to this


 :usercode
 if !%startnum% == ! goto cont
 if !%startnum% == !run goto cont
 if not !%startnum% == !%count% goto userend
 set startnum=run
 :cont
 if exist %dir%\%prefix%%count%.%ext% goto userend
 if not exist %fname% exit
 copy %fname% %dir%\%prefix%%count%.%ext% > nul
 del %fname%
 exit
 :userend

Note that "> nul" has been added to the copy command and the two announcements have been removed - those modifications remove all screen messages except error messages.

Another use of FOR is as a loop counter:


 for %%a in (! ! ! ! ! ! ! ! ! !) do something
does whatever you tell it to ten times, once for each bang character in the set.

A more elaborate bang counter that takes a numerical argument (0 - 10) is


 @echo off
 set target=
 if %1!==0! set target=
 if %1!==1! set target=!
 if %1!==2! set target=!!
 if %1!==3! set target=!!!
 if %1!==4! set target=!!!!
 if %1!==5! set target=!!!!!
 if %1!==6! set target=!!!!!!
 if %1!==7! set target=!!!!!!!
 if %1!==8! set target=!!!!!!!!
 if %1!==9! set target=!!!!!!!!!
 if %1!==10! set target=!!!!!!!!!!
 set count=
 shift
 :loop
 if %count%!==%target%! goto end
 set count=%count%!
 REM  user code goes here  - comment out or remove the following line 
 REM if you don't want to see the count process.
 echo %count%
 goto loop
 :end
Obviously that can be used only for rather small numbers, a small range of numbers or a small number of non-sequential numbers. These fragments (just the translation code) illustrate the latter two uses:

 @echo off
 set target=
 if %1!==23! set target=!!!!!!!!!!!!!!!!!!!!!!!
 if %1!==24! set target=!!!!!!!!!!!!!!!!!!!!!!!!
 if %1!==25! set target=!!!!!!!!!!!!!!!!!!!!!!!!!
 if %1!==26! set target=!!!!!!!!!!!!!!!!!!!!!!!!!!

 @echo off
 set target=
 if %1!==1! set target=!
 if %1!==9! set target=!!!!!!!!!
 if %1!==23! set target=!!!!!!!!!!!!!!!!!!!!!!!

There is also the undocumented syntax (completely broken in Win95 and NT) that places a '/' in front of a string. This syntax has the curious property of calling the DO clause twice - once with the character following the '/', and the second time with the rest of the string. This is handy for stripping leading characters and for reformatting strings. The following code strips the first four digits off a twelve digit Ethernet address to make an eight digit string for use as a directory name:


 @echo off
 %1 %2 %3 %4     REM You are not expected to understand this batch file
 goto pass0
 :pass1
 for %%b in (/%SHRTNM%) do call %0 goto pass2 %%b
 goto end
 :pass2
 goto pass2%pxt%
 :pass2a
 set pxt=b
 goto end
 :pass2b
 set pxt=a
 set shrtnm=%3
 goto end
 :pass0
 set pxt=a
 REM network installation code omitted - it generates the value of STATION 
 REM as the Ethernet address
 set shrtnm=%STATION%
 for %%a in (1 2 3 4) do call %0 goto pass1
 set pxt=
 REM more code omitted
 :end
That is an edited version of a real batch file - the comment is for the benefit of users who don't have enough to do to keep them busy without messing around with the machine's configuration and setup files.

Other examples of the use of FOR can be found throughout this book, but there is in interesting use for reversing a string and adding spaces in the section on Decimal Addition.


GOTO
is the command we are taught to avoid in structured programming. Well, we don't really have a choice in batch language, since if we want structured code, we have to write the structures using GOTO. Basically, GOTO is a jump within a batch file. There are plenty of examples throughout the code here. If the target is below the jump, COMMAND.COM need only read and parse the lines between the jump and the target, but if it is above the jump, COMMAND.COM must read to the end, then start over. For large backward jumps, it is well to reinvoke the batch file and have a vector at the top to handle the actual jump, which is then a forward jump:


 @echo off
 %1 %2
 :label1
 REM some code
 %0 goto label1
 REM more code
 :end

Note that either a space or a colon can be used as the separator between "goto" and the target label. This is particularly useful in constructions involving FOR:


 for %%a in (echo goto:end) do %%a Message
will first echo the message then goto the :end label.


IF ERRORLEVEL
is normally used to cause the batch file to take the appropriate action based on the success or failure of an external executable program, though it can, in some cases, be used to select the proper code based on the nature of the failure.

The only available test for use with ERRORLEVEL is an

 if errorlevel => x 
test (and it's negation, of course). ERRORLEVEL cannot be assigned to a variable. The standard forms of the test are

 if errorlevel 4 goto el4
 if errorlevel 3 goto el3
 if errorlevel 2 goto el2
 if errorlevel 1 got0 el1
Note that the highest number of interest must be tested first because the test returns true for any value equal to or greater than the test value. The form

 if not errorlevel 4 goto nel4
performs a < test.

 if errorlevel 4 if not errorlevel 5 got el4
 
and similar constructs perform an exact equality test.

A special case is the kind of program that returns information, such as what key was pressed, as the ERRORLEVEL.


 @echo off
 xcopy e:\temp\*.* c:\temp\ /s
 if not errorlevel 1 goto success
 echo No files found to copy or XCOPY failed
 goto end
 :success
  ... do whatever you need to do with the copies
 :end
Note that if the /a switch had been used with XCOPY, ERRORLEVEL 0 would not necessarily mean that it copied any files, only that some files were found before the archive attribute was checked.


IF EXIST foo
allows executation of a command, conditional on the existence of a named file. The filespec and or the command can be variable, but here we address the hard coded case.


 if exist foo del foo
is a common usage of the IF EXIST construct. It avoids the "File not found" error message if the file given by foo does not exist, by attempting to delete the file only if it actually exists. This is frequently used with foo being a wild card pattern. A number of variations of this single conditional executation construct are given in the Examples section. The negation can also be used to verify that a file does not exist before doing something that requires that condition:

 if not exist foo.bat copy \bin\foo.bat

The command in the IF EXIST construct can be CALL or GOTO, which allow something like procedure and function calls. While the first example generate syntax errors if the negation operator is used, commands that do not act on the file tested do not, and use of negation can often simplify the structure. Here a real world example is used, though only in outline form: it is frequently necessary to determine if some external utility succeeded, but the utility does not return a useful ERRORLEVEL - the output from the command can be filtered through FIND, FIND's output routed to a file, and the file tested for content by attempting to copy it. This code determines in the file TEST.DAT contains the phrase "the quick brown fox" (using the case insensitive match feature of FIND).


 @echo off
 set response=Phrase not found
 find /i "the quick brown fox" test.dat > }{.1
 copy }{.1 }{.2
 if not exist }{.2 goto done
 del }{.2
 set response=Phrase found
 :done
 del }{.1
 echo %response%
 set response=
 :end
Note that if the negation operator (NOT) had not been used, it would have been necessary to apply special handling to the deletion of }{.2, or to use a more complicated structure with multiple jumps, rather than the fall through structure actually used, as in this example

 @echo off
 find /i "the quick brown fox" test.dat > }{.1
 copy }{.1 }{.2
 if exist }{.2 goto exists
 echo Phrase not found
 goto done
 :exists
 echo Phrase found
 del }{.2
 :done
 del }{.1
 :end


IF foo == bar
does string comparisons. The strings can be command line arguments, environment variables, or string literals. A very old example is the RUN.BAT program that combines a number of batch files into one and uses the first command line argument to vector to the code needed for the case in hand.


 @echo off
 if "%1" == "ed" goto ed
 if "%1" == "c" goto c
 echo ERROR: the %1 argument cannot be identified.
 goto end
 :ed
  ... code to set up for, launch, and clean up after the text editor
 goto end
 :c
  ... code to set up for, launch, and clean up after the c compiler and its IDE
 goto end
 :end
A common use is to control program flow on the basis of environment variables:

 if "%temp%" == "" goto novar
(The "" marks allow comparison of null strings since they become part of the string - if %temp% has not been set to something, the above becomes ""=="" after normalizing and substituting by the command processor.

A variation is to convert the argument(s) to all caps before making the comparison - see: "Examples". The variable command syntax (to be elaborated later) can be used here as well.


MOVE has some uses that aren't obvious from its name, but parallel some of the functionality of the unix version: it not only moves files but also renames directories - but it won't move directories. MOVE takes only one switch: /y (or /-y to override a /y switch in the COPYCMD variable (both COPY and MOVE use the same variable so they have to have the same switches active for both)). The syntax is


 MOVE [/Y | /-Y] [drive:][path]dirname1 dirname2
(as given my MS) but more correctly

 MOVE [/Y | /-Y] [drive:][path]dirname1 [drive:][path]dirname2
for renaming (but not moving) a directory - note that the optional parts of the syntax have to appear in both source and target specs if they are used in either and have to be the same in both.

 MOVE [/Y | /-Y] [drive:][path]filename1[,...] destination
Moves and/or renames a file. "destination" can be almost anything that makes sense, but if the destination doesn't exist and is like a filename it will be taken as a filename in the current directory - if the file is in the current directory the result is the same as a REN. If the file is not in the current directory it will be moved there. If everything is specified and the target directory exists, the file will be moved there, even to a different drive. MOVE is an external command (MOVE.EXE) and returns errorlevels: 0 for success and 1 for error. This may have some subtle uses in batch files, but I haven't had the time to explore the implications.

There is quite a bit on information in HELP about MOVE, and most of it is correct though (of course) incomplete.


Useful things you can do with the PROMPT

There are two categories of things to do with the PROMPT command: issue strings containing hard to deal with Escape characters to the console and obtain information for use in the batch file (or elsewhere). The former is most frequently used to send ANSI Escape sequences to ANSI.SYS (a replacement console device). This is easy:

 @echo off
 set oldprompt=%prompt%
 prompt $e[2J
 echo on

 @echo off
 set prompt=%oldprompt%
 set oldprompt=
 :end
clears the screen. The Escape sequences are more often used to control colors and/or cursor position, though - just change the part after "$e[" to whatever you need.

Since we want the changed prompt to be active only once, we save the old string, turn echoing on, generate a pure prompt with a blank line, then turn echoing off again, and restore the original prompt string.

Using the prompt to get information is a bit trickier, since we have to redirect the prompt into a file, and that can't be done, except by spawning a secondary command processor and redirecting its output, which leaves us with the problem of getting the information back into the program:


 @echo off
 %1 %2
 set oldprompt=%prompt%
 prompt %0 goto pass2 $d $t
 command /c%0 goto dummy > }{.bat
 set prompt=%oldprompt%
 set oldprompt=
 }{
 goto end
 :pass2
 set stamp=%4/%5
 goto end
 :dummy
 echo on

 @echo off
 :end
generates a date/time stamp of the form 09-09-1995/19:39:05.29 (you could strip off just the characters form the time that you wanted with some of the string processing code found in many of the examples here and elsewhere in this book. Note that %3 is omitted from the stamp: it is the day name.

The problem of getting the information back into the batch file is dealt with here by including the necessary commands to reinvoke the batch file and vector it to the proper section of code in the changed prompt string, and therefore in the batch file that the prompt is redirected to. The invocation of COMMAND.COM with the arguments given causes it to reinvoke the batch file and vector to the section that turns echoing back on, generates a prompt with a blank line, then turns echoing back off, and exits (which causes the secondary command processor to terminate as well, which returns us to the line following the invocation of the command processor. As in the earlier example, we have to save and restore the original prompt string. The changes should be effective for as few commands as possible, so that if the program abends, the chances of having a corrupt prompt are low, though in reality, the only place where an abend is likely (from a user issued ^C) is when the changed prompt is being written to the file. However, during testing, with all echoing enabled, ^C would be active everywhere, and would also be quite likely to occur.

Variations on this theme give you the day name from $d and %3, the DOS version from $v and %5, the drive letter from $n and %3, or the drive and path with $p and %3.

I have seen a batch file that does all of this at once, putting the various elements into separate environment variables (the structure was completely different, and rather interesting, but not quite my style).


Redirection and pipes are operators, not commands. They tell COMMAND.COM to connect the input or output of programs to either files (redirection) or other programs (pipes). This works only if the program uses the standard input and output streams for its console I/O. In general, programs with fancy screens don't and those with crude command line interfaces do. Most DOS utilities do. Nearly all filters do (MORE is a filter).

Pipes use the | symbol to connect the output of one program or command to the input of another. Quite long chains can be built this way. A very common use is to pipe the output of a command or program through FIND to strip out everything except the specific line(s) wanted.

The input redirection operator is < and the output redirection operators are > and >>. < connects a file (or device) to the input stream of a program so that you can put responses to prompts in a file and run the program automatically. Input redirection is seldom used these days because few programs use the standard input stream (STDIN) and few users understand the benefits. It is used in this book most often in the LOADFIX/DATE method of working with lists. Output redirection is more generally used - it is useful for putting directory listings into files and for creating and filling files from inside batch programs, using the ECHO command and redirection to change the destination of the ECHO to a file instead of the console. > causes the file to be created or truncated - multiple ECHOs to the same file will leave the file with just the last one in it while >> causes whatever is redirected to be appended to the end of the file. >> is useful for building batch files from within batch files: the file is created with a > redirection and the remaining ECHO lines use >> to add the lines to the end of the file. >> is also useful for creating and adding to log files:


 echo. | date | find "Current" >> foo.log
 echo. | time | find "Current" >> foo.log
 echo. >> foo.log
assumes that the user will delete or rename the file from time to time - otherwise it can grow to fill the drive. It puts just the date line ("Current date is ...") and the time line ("Current time is ...") followed by a blank line into the log file. The ECHO. command generates just an <Enter> which is piped to the DATE and TIME commands to respond to the "Enter new ..." prompts that would otherwise stop the program and wait for the user to hit <Enter>. The third use causes a blank line to be appended to the end of the file. The same effect can be had, though more slowly, by creating a file containing just a blank line and redirecting it to the input of the DATE and TIME commands and TYPEing it to the target file:

 date < response.fil | date | find "Current" >> foo.log
 time < response.fil | date | find "Current" >> foo.log
 type response.fil >> foo.log

Note that output redirection and pipes work only with the standard output stream (STDOUT) and the standard input stream (STDIN).

There are many gotchas and subtleties to redirection and pipes: in complex commands only the output of the first command is redirected, and that is often something like "if exist or FOR that doesn't even have an output in the usual sense. Sometimes this effect is useful, but more often it's a nuisance. One time when it is very useful is when it is desirable to put the total output from a batch file into a file or through a filter. In that case, the batch file is run from a secondary command processor and the output of that is redirected or piped. See the section on Debugging batch files, and the DIRX.BAT program for more explanation and examples. The latter works around most of the gotchas that afflict redirection and pipes


REM
is the comment (REMark) marker. "::" works better for pure comments (that's really a defective label, and isn't processed at all), but REM actually has uses a a command:


 @echo off
 REM > temp.tmp
 :echo 
has the remarkable property of creating a zero length file named TEMP.TMP, which can then be used in an IF EXIST test, where it will test as existing, but doesn't actually consume disk space, only a directory entry. The curious thing about that use of REM is that you can still include a comment string in the remark without having it go into the target file.

 @echo off
 REM this is a test > temp.tmp
 :end
still creates a zero length file named TEMP.TMP.

The standard syntax is @echo off REM this is a comment :end which has no effect on the program except to slow it down slightly more than the "::" syntax:


 @echo off
 :: this is also a comment, though COMMAND.COM thinks it's a defective label
 :end
Note: it has been reported in newsgroups that ';' is also a comment marker - this is not true for MSDOS 6.22.

REN and RENAME are variant names for the same command - the command to rename files (but not directories - use MOVE for that.

The usage and syntax are both simple and it's functionality is very limited. The syntax is


 RENAME [drive:][path]filename1 filename2
 REN [drive:][path]filename1 filename2
and the effect is to change just the name and/or extension of the specified file(s) - you cannot change the directory part of a filespec with REN - you can't even specify a path in the target filename. This function will rename zero length files - it works only on the directory entry and doesn't care what, if anything, is in the file.

There isn't much that can be done with the command other than its intended use.

REN and RENAME are internal COMMAND.COM functions and therefore return no errorlevel.


SHIFT
has only one function: it relocates the window of accessibility of command line arguments toward the end of the command tail. The only arguments ever available are %0 through %9. Initially %0 is the first thing on the command line (the name of the program) and the arguments %1 through %9 are the next nine fields on the command line (the first nine arguments to the program). SHIFT moves this access window one position to the right (or conversely, the arguments one position to the left) so that each argument refers to the item that was to its right. This is used in Decimal Addition to position the ten items in the look up table so that they line up with the digits 0 through 9 for indexes [0] through [9]. This batch file (name it ZERO.BAT) illustrates the concept by reinvoking itself with an argument string and shifting through it (%10 is included to show that %9 really is the upper limit - %10 resolves to %1 followed by a literal '0' character):


 ZERO.BAT
  @echo off
  %fork%
  set fork=goto pass2
  %0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  :pass2
  echo.
  echo Unshifted:
  echo %%0=%0 %%1=%1 %%2=%2 %%3=%3 %%4=%4
  echo %%5=%5 %%6=%6 %%7=%7 %%8=%8 %%9=%9
  echo %%10=%10
  echo.
  shift
  echo Shifted once:
  echo %%0=%0 %%1=%1 %%2=%2 %%3=%3 %%4=%4
  echo %%5=%5 %%6=%6 %%7=%7 %%8=%8 %%9=%9
  echo %%10=%10
  echo.
  shift
  echo Shifted twice:
  echo %%0=%0 %%1=%1 %%2=%2 %%3=%3 %%4=%4
  echo %%5=%5 %%6=%6 %%7=%7 %%8=%8 %%9=%9
  echo %%10=%10
  echo.
  shift
  echo Shifted three times:
  echo %%0=%0 %%1=%1 %%2=%2 %%3=%3 %%4=%4
  echo %%5=%5 %%6=%6 %%7=%7 %%8=%8 %%9=%9
  echo %%10=%10
  echo.
  shift
  shift
  shift
  shift
  echo Shifted seven times:
  echo %%0=%0 %%1=%1 %%2=%2 %%3=%3 %%4=%4
  echo %%5=%5 %%6=%6 %%7=%7 %%8=%8 %%9=%9
  echo %%10=%10
  echo.
  shift
  shift
  shift
  shift
  shift
  echo Shifted twelve times:
  echo %%0=%0 %%1=%1 %%2=%2 %%3=%3 %%4=%4
  echo %%5=%5 %%6=%6 %%7=%7 %%8=%8 %%9=%9
  echo %%10=%10
  echo.
  set fork=
  :end


There are a few other commands that are seldom used outside of batch files. Some, such as LOADHIGH, SUBST, SETVER, and the like are system setup commands, and really don't have a place in a discussion of batch files as batch files, but belong in discussions of system configuration - they will be ignored in this treatise. There is one other, SET, which while technically a COMMAND.COM internal command, rather than a batch file intrinsic command, will be treated here because it is seldom used from the command line and is essential to the operation of the majority of batch files.

SET
is the command that places a string into a named record in the environment. It is discussed more fully in the section devoted to Variables, and is illustrated throughout this treatise.

  ** Copyright 1995, Ted Davis - all rights reserved ** 

Input and feedback from readers are welcome. NOTE: the subject of the message must contain the word "batch" for the message to get past the spam filter.

Back to the Table of Contents page

Back to my personal links page - back to my home page