<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"->
<HTML>
<HEAD>
<TITLE>DOS Batch Language: Internal and Intrinsic Commands</TITLE>
</HEAD>
<BODY>

<CENTER><H4>Internal and Intrinsic Commands</H4></CENTER>
<UL>
<LI><A HREF="#call"><B>CALL</B></A>
<LI><A HREF="#cd"><B>CD</B></A>
<LI><A HREF="#dir"><B>DIR</B></A>
<LI><A HREF="#echo"><B>ECHO</B></A>
<LI><A HREF="#for"><B>FOR</B></A>
<LI><A HREF="#goto"><B>GOTO</B></A>
<LI><A HREF="#ifer"><B>IF ERRORLEVEL</B></A>
<LI><A HREF="#ifx"><B>IF EXIST foo</B></A>
<LI><A HREF="#ifm"><B>IF foo == bar</B></A>
<LI><A HREF="#move"><B>MOVE</B></A>
<LI><A HREF="#prompt"><B>PROMPT</B></A>
<LI><A HREF="#ren"><B>RENAME (REN)</B></A>
<LI><A HREF="#redirect"><B>Redirection and pipes</B></A>
<LI><A HREF="#rem"><B>REM</B></A>
<LI><A HREF="#shift"><B>SHIFT</B></A>
<LI><A HREF="#set"><B>SET</B></A>
</UL>


<P><A NAME="call"><B>CALL</B></A><BR> 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 <B>COMMAND.COM</B>) so that execution can be resumed at the next line in the file, when 
the called batch file terminates.  Since each <B>CALL</B> consumes some memory until it is 
cleared by the return of the called program, there is a finite limit to the number 
of <B>CALL</B>s that can be nested.  I don't know what this limit is, or any other details 
of how the call in managed internally by <B>COMMAND.COM</B>.  You can demonstrate the 
existence of the limit with this program
<PRE><CODE>
 @echo off
 call %0
 :end
</CODE></PRE>
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).
<PRE><CODE>
 H:\>test
Insufficient memory
 H:\>
</CODE></PRE>
<B>CALL</B> 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 <A HREF="defs1.htm#recurs">recursion</A>.  <B>CALL</B> causes <B>COMMAND.COM</B> 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.  <B>CALL</B> can also be 
used to invoke executables, though <B>COMMAND.COM</B> doesn't seem to do anything different when you do.  
However, there is a certain flexibility in using <B>CALL</B> 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 
<B>CALL</B> 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.  <B>CALL</B> also is useful in <B>FOR</B> 
loops both in batch files and from the command line to prevent the loop from terminating
prematurely when the action is a batch file (<CODE>FOR %a in (foo.bat bar.bat baz.bat) do %a</CODE> will 
execute only FOO, but <CODE>FOR %a in (foo.bat bar.bat baz.bat) do call %a</CODE> will execute 
all three).</P>
<HR>
<P><A NAME="cd"><B>CD</B></A> 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: 
<PRE><CODE>
 c:
 cd d:\foo
</CODE></PRE>
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.</P>
<P> 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:</P>
<PRE><CODE>
 @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
</CODE></PRE>
<P>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. 
<HR>
<P><A NAME="dir"><B>DIR</B> 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:
<PRE><CODE>
 dir *.exe *.com *.bat *.pif
</CODE></PRE>
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: <A HREF="exmp1.htm#dirx">DIRX.BAT</A>.</P>
<P>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 <A HREF="dirhlp.txt">separate file</A> 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 
<PRE><CODE>
 dir /? > dirhlp.txt
</CODE></PRE></P>
<HR>
<P><A NAME="echo"><B>ECHO</B></A> (on, off, or text)<BR> is really two commands: one to control 
the <B>ECHO</B> 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 <B>ECHO</B> status has no effect on <B>ECHO</B>ed 
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 <B>COMMAND.COM</B> remains in batch mode.  Note that this does not affect secondary 
command processors:
<PRE><CODE>
 @if "%1" == "" echo off
 if  "%1" == "" command /c%0 foo
 :end
</CODE></PRE></P>

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

<PRE><CODE>
 @echo off
 echo. | date
 echo. | time
 :end
</CODE></PRE></P>

<P><B>ECHO</B> 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:
<PRE><CODE>
 echo y | del c:\temp\*.*
</CODE></PRE>
But beware - always specify the exact drive and directory in full - <B>never</B> do it 
this way
<PRE><CODE>
 set TEMP=c:\temp
 echo y | del %temp%\*.*
</CODE></PRE>
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.</P>

<P><B>ECHO</B>, without any arguments, simply displays the echo status: either ON or OFF.</P>
<P>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:</P>
<PRE><CODE>
 for %%a in (foo) do echo %%a > baz
 if not !%1 == ! echo foo > bar
</CODE></PRE>
<P>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:</P>
<PRE><CODE>
 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
</CODE></PRE>
<HR>

<P>The <B><A NAME="for"><B>FOR</B></A> x in (set) do</B><BR> 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:
<PRE><CODE>
 @echo off
 for %%a in (*.bat) do if not exist .\bak\%%a copy %%a .\bak
 :end
</CODE></PRE>
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 <A HREF="variable.htm">variable</A> 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 <B>FOR</B> in the same file).

<B>FOR</B> also has other uses, for example, to process a list of items:
<PRE><CODE>
 for %%a in (*.bat *.exe, *.com) do if not exist .\bak%%a copy %%a .\bak
</CODE></PRE>
does what the first example does, except for all three of those extensions.</P>

<P><A NAME="count">The</A> list (set) need not have anything to do with files, as the following 
three digit counter illustrates:
<PRE><CODE>
 @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
</CODE></PRE>

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.</P>
<P><A NAME="rennnn">A</A> more usable form of the above (called <B>RENnnn.BAT</B>) 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.</P>
<PRE><CODE>
 @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
</CODE></PRE>
<P>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.</P>
<P>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</P>
<PRE><CODE>
 :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
</CODE></PRE>
<P>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.</P>
<P><A NAME="bang">Another</A> use of <B>FOR</B> is as a loop counter:
<PRE><CODE>
 for %%a in (! ! ! ! ! ! ! ! ! !) do something
</CODE></PRE>
does whatever you tell it to ten times, once for each bang character in the 
set.</P>
<P>A more elaborate bang counter that takes a numerical argument (0 - 10) is
<PRE><CODE>
 @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
</CODE></PRE>
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:
<PRE><CODE>
 @echo off
 set target=
 if %1!==23! set target=!!!!!!!!!!!!!!!!!!!!!!!
 if %1!==24! set target=!!!!!!!!!!!!!!!!!!!!!!!!
 if %1!==25! set target=!!!!!!!!!!!!!!!!!!!!!!!!!
 if %1!==26! set target=!!!!!!!!!!!!!!!!!!!!!!!!!!
</CODE></PRE>
<PRE><CODE>
 @echo off
 set target=
 if %1!==1! set target=!
 if %1!==9! set target=!!!!!!!!!
 if %1!==23! set target=!!!!!!!!!!!!!!!!!!!!!!!
</CODE></PRE>

</P>

<P>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:

<PRE><CODE>
 @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
</CODE></PRE>
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.</P>

<P>Other examples of the use of <B>FOR</B> can be found throughout this book, but
there is in interesting use for reversing a string and adding spaces in the 
section on <A HREF="dadd.htm#strings"><EM>Decimal Addition</EM></A>.</P>
<HR>

<P><A NAME="goto"><B>GOTO</B></A><BR> 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 <B>GOTO</B>.  Basically, 
<B>GOTO</B> is a jump within a batch file.  
There are plenty of examples throughout the code here.  If the target is below 
the jump, <B>COMMAND.COM</B> need only read and parse the lines between the jump and the 
target, but if it is above the jump, <B>COMMAND.COM</B> must read to the end, then 
start over.  For large backward jumps, it is well to reinvoke the batch file and
have <A HREF="recurs.htm">a vector at the top</A> to handle the actual jump, 
which is then a forward jump:
<PRE><CODE>
 @echo off
 %1 %2
 :label1
 REM some code
 %0 goto label1
 REM more code
 :end
</CODE></PRE></P>
<P>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 <B>FOR</B>: 
<PRE><CODE>
 for %%a in (echo goto:end) do %%a Message
</CODE></PRE>
will first echo the message then goto the :end label.</P>

<HR>
<P><A NAME="ifer">IF ERRORLEVEL</A><BR>
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.<P>

<P>The only available test for use with <B>ERRORLEVEL</B> is an 
<PRE><CODE> if errorlevel =&GT x </CODE></PRE> test (and it's negation, 
of course).  <B>ERRORLEVEL</B> cannot be assigned to a variable.  
The standard forms of the test are 
<PRE><CODE>
 if errorlevel 4 goto el4
 if errorlevel 3 goto el3
 if errorlevel 2 goto el2
 if errorlevel 1 got0 el1
</CODE></PRE>
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 
<PRE><CODE>
 if not errorlevel 4 goto nel4
</CODE></PRE>
performs a &LT test.

<PRE><CODE>
 if errorlevel 4 if not errorlevel 5 got el4
 </CODE></PRE>
and similar constructs perform an exact equality test.


<P>A special case is 
the kind of program that returns information, such as what key was 
pressed, as the ERRORLEVEL.
<PRE><CODE>
 @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
</CODE></PRE>
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. </P>


<HR>
<P><A NAME="ifx">IF EXIST foo</A><BR>
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.</P>

<P><PRE><CODE>
 if exist foo del foo
</CODE></PRE>

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 <A HREF="exmp1.htm">Examples</A> section.  The negation can 
also be used to verify that a file does not exist before doing something 
that requires that condition:
<PRE><CODE>
 if not exist foo.bat copy \bin\foo.bat
</CODE></PRE></P>

<P>The command in the IF EXIST construct can be <B>CALL</B> or <B>GOTO</B>, 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).
<PRE><CODE>
 @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
</CODE></PRE>
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
<PRE><CODE>
 @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
</CODE></PRE></P>
<HR>
<P><A NAME="ifm"><B>IF foo == bar</B></A><BR> 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.
<PRE><CODE>
 @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
</CODE></PRE>
A common use is to control program flow on the basis of environment variables:
<PRE><CODE>
 if "%temp%" == "" goto novar
</CODE></PRE>
(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.</P>
<P>
A variation is to convert the argument(s) to all caps before 
making the comparison - see: "<A HREF="exmp1.htm">Examples</A>".  The variable command 
syntax (to be elaborated later) can be used here as well.</P>
<HR>
<P><A NAME="move">MOVE</A> 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 <B>move</B> 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
<PRE><CODE>
 MOVE [/Y | /-Y] [drive:][path]dirname1 dirname2
</CODE></PRE>
(as given my MS) but more correctly
<PRE><CODE>
 MOVE [/Y | /-Y] [drive:][path]dirname1 [drive:][path]dirname2
</CODE></PRE>
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.
<PRE><CODE>
 MOVE [/Y | /-Y] [drive:][path]filename1[,...] destination
</CODE></PRE>
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 <B>current</B> directory - if the file is in the current directory 
the result is the same as a <A HREF="#ren">REN</A>.  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.</P>
<P>There is quite a bit on information in HELP about MOVE, and most of it is correct though (of course)
incomplete.</P>
<HR>
<P><A NAME="prompt">Useful</A> things you can do with the <B>PROMPT</B></P>
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:
<PRE><CODE>
 @echo off
 set oldprompt=%prompt%
 prompt $e[2J
 echo on

 @echo off
 set prompt=%oldprompt%
 set oldprompt=
 :end
</CODE></PRE>
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.</P>

<P>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.</P> 

<P>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:
<PRE><CODE>
 @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
</CODE></PRE>
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.</P>

<P>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.</P>

<P>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.</P>

<P>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).</P>

<HR>
<P><A NAME="redirect"><B>Redirection</B> and <B>pipes</B></A> 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).</P>
<P>Pipes use the <CODE>|</CODE> 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.</P>
<P>The input redirection operator is <CODE>&LT</CODE> and the output redirection 
operators are <CODE>&GT</CODE> and <CODE>&GT&GT</CODE>.  &LT 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 <A HREF="listp1.htm">LOADFIX/DATE method</A> 
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.  &GT 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 
&GT&GT causes whatever is redirected to be appended to the end of the file.  &GT&GT is 
useful for building batch files from within batch files: the file is created with a &GT 
redirection and the remaining ECHO lines use &GT&GT to add the lines to the end of 
the file.  &GT&GT is also useful for creating and adding to log files:
<PRE><CODE>
 echo. | date | find "Current" >> foo.log
 echo. | time | find "Current" >> foo.log
 echo. >> foo.log
</CODE></PRE>
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 &LTEnter&GT 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 &LTEnter&GT.  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:
<PRE><CODE>
 date < response.fil | date | find "Current" >> foo.log
 time < response.fil | date | find "Current" >> foo.log
 type response.fil >> foo.log
</CODE></PRE></P>
<P>Note that output redirection and pipes work only with the standard output stream 
(STDOUT) and the standard input stream (STDIN).</P>
<P>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 
"<CODE>if exist</CODE> or <CODE>FOR</CODE> 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 <A HREF="debuging.htm">Debugging batch files</A>, and the <A HREF="exmp1.htm#dirx">DIRX.BAT</A> program 
for more explanation and examples.  The latter works around most of the gotchas that 
afflict redirection and pipes</P>
<HR>
<P><A NAME="rem"><B>REM</B></A><BR> 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:

<PRE><CODE>
 @echo off
 REM > temp.tmp
 :echo 
</CODE></PRE>
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.  
<PRE><CODE>
 @echo off
 REM this is a test > temp.tmp
 :end
</CODE></PRE>
still creates a zero length file named TEMP.TMP.</P>
<P> The standard syntax is
</CODE></PRE>
 @echo off
 REM this is a comment
 :end
</CODE></PRE>
which has no effect on the program except to slow it down slightly more than the "::" 
syntax:
<PRE><CODE>
 @echo off
 :: this is also a comment, though COMMAND.COM thinks it's a defective label
 :end
</CODE></PRE>
Note: it has been reported in newsgroups that ';' is also a comment marker - this 
is not true for MSDOS 6.22.
<HR>
<P><A NAME="ren"><B>REN</B> and <B>RENAME</B></A> are variant names for the same command -
the command to rename files (but not directories - use <A HREF="#move">MOVE</A> for that.</P>
<P>The usage and syntax are both simple and it's functionality is very limited.  
The syntax is 
<PRE><CODE>
 RENAME [drive:][path]filename1 filename2
 REN [drive:][path]filename1 filename2
</CODE></PRE>
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.</P>
<P>There isn't much that can be done with the command other than its intended use.</P>
<P>REN and RENAME are internal COMMAND.COM functions and therefore return no errorlevel.
<HR>
<P><A NAME="shift"><B>SHIFT</B></A><BR> 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).  <B>SHIFT</B> 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 <A HREF="dadd.htm"><EM>Decimal Addition</EM></A> 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):

<PRE><CODE>
 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
</CODE></PRE></P>

<HR>
<P>There are a few other commands that are seldom used outside of batch files.  Some, such 
as <B>LOADHIGH</B>, <B>SUBST</B>, <B>SETVER</B>, 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, <B>SET</B>, which while technically a </B>COMMAND.COM</B> 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.</P>

<P><A NAME="set"><B>SET</B></A><BR> is the command that places a string into a named record 
in the <A HREF="defs1.htm#environ">environment</A>.  It is discussed more fully in the 
section devoted to <A HREF="variable.htm"><EM>Variables</EM></A>, and is illustrated 
throughout this treatise.</P>


<PRE>  ** Copyright 1995, Ted Davis - all rights reserved ** </PRE>

<P><A HREF="mailto:tdavis@umr.edu">Input and feedback</A> from readers are welcome.</P>
<P>Back to the <A HREF="http://www.maem.umr.edu/~batch/index.htm">Table of Contents</A> page
<P>Back to my <A HREF="http://www.maem.umr.edu/~tdavis/ted2.htm">personal links</A> page - back to my <A HREF="http://www.maem.umr.edu/~tdavis/tdavis.htm">home page</A></P>
</BODY>
</HTML>
