Timo Salmi's Assorted Batch Tricks


Professor Timo Salmi
Department of Accounting and Business Finance
University of Vaasa, Finland

Co-moderator of news:comp.archives.msdos.announce
http://garbo.uwasa.fi/
ftp://garbo.uwasa.fi/

All rights reserved
Copyright (c) 1993-1999 by Timo Salmi
 ....................................................................
 Prof. Timo Salmi   Co-moderator of news:comp.archives.msdos.announce
 Moderating at ftp:// & http://garbo.uwasa.fi/ archives 193.166.120.5
 Department of Accounting and Business Finance  ; University of Vaasa
 mailto:ts@uwasa.fi   ; FIN-65101,  Finland
 Spam foiling in effect.  My email filter autoresponder will return a
 required email password to users not yet in the privileges database.
 ....................................................................

 ___________________________________________________________

  This file belongs with TSBAT*.ZIP. Please do not distribute
  this 1BATFAQ file separately! If you see this file
  distributed alone, please alert the SysAdmin immediately.
 ___________________________________________________________
Introduction  Index  Articles  Download the text file version with samples and utilities 


Introduction


This file contains assorted batch tricks. The items are in no
particular order. Many, but not all, have been used in the
TSBAT*.ZIP collection of batches. Likewise, there are some useful
further tricks, not documented here, to be found in the TSBAT
batches.

Many users have sent me useful suggestions and their own alternative
or further solutions. My best thanks for the material. You can find
much of this feedback and the other users' solutions stored in the
ftp://garbo.uwasa.fi/pc/pd2/tspost00.zip files. The items by the
other users are listed at the end of tsbat.inf included in this
collection.

For further batch programming material via the World Wide Web
connect to http://garbo.uwasa.fi/pc/batchutil.html. Also, connect to
my home page http://www.uwasa.fi/~ts/ then click my collection of
HTTP links and find the section on programming.

You are free to quote brief passages from this 1BATFAQ.TXT file
provided you clearly indicate the source with a proper
acknowledgment.

Comments and corrections are solicited. But if you wish to have
individual batch programming consultation, please rather post your
question to a Usenet newsgroup like news:comp.os.msdos.programmer or
news:alt.msdos.batch. It is much more efficient than asking me by
email. I'd like to help, but I am very pressed for time. I prefer to
pick the questions I answer from the Usenet news. Thus I can answer
publicly at one go if I happen to have an answer. Besides,
newsgroups have a number of readers who might know a better or an
alternative answer. Also please see item #56. Don't be discouraged,
though, if you get a reply like this from me. I am always glad to
hear from fellow batch file users.

A special Windows 95 note: Some of the tricks in this collection
will not work, or will not work without adjustments, for MS-DOS run
in a Windows 95 box. One subtle pitfall I have know of is that
Windows 95 uses long file names while the information in this
collection is based on the 8+3 filename convention. This will affect
some of the batches. And so on. The same goes all the more for
Windows NT.

--------------------------------------------------------------------
Introduction  Index  Articles  Download the text file version with samples and utilities 


Index


NOTE:       To search this document for a specific keyword, press CTRL+F on your keyboard to use your browser's text search capability.


1) How can I make "@echo off" MS-DOS version independent?

2) Deleting all files without being prompted "Are you sure (Y/N)?"

3) Is it possible to nest for loops in batch files?

4) How can I check in a batch whether a directory exists?

5) Checking that a program is available at the current directory or at path

6) Is it possible to use subroutines and recursion in batches?

7) How can I convert a lowercase parameter to uppercase?

8) Is there an easy way to append a new directory to the path?

9) How can I compare if two files two files are identical?

10) Writing an empty line to the screen. How is that done?

11) A tip: Customizing the pause message

12) A tip: Complicated renaming of files with for

13) How can I check if the file name given included wildcards?

14) Is it possible to prevent the user from breaking the batch?

15) Can I prevent a break from bypassing the autoexec.bat?

16) How can I extract the extension of a file name?

17) Information on the quote character %

18) Eliminating auxiliary batches (making do with the main batch)

19) Utilizing the subst command in paths

20) How can I run a batch once a week (testing for the weekday)

21) How can I test if a given file name includes the path?

22) How can I display the time without having to press enter?

23) Alternatives for testing for the errorlevel value

24) About redirecting a batch file's output

25) How can I test if my batch has sufficient environment space?

26) Is there a simple trick to "disable" or hide a drive?

27) How can I send an escape sequence to the printer?

28) Is it possible to create a random string in a batch?

29) Is it possible in a batch to find out the length of a string?

30) How to obtain the MS-DOS version into an environment variable?

31) How can I find out the number of regular files on a drive?

32) How can I use a batch to augment line numbers to my text file?

33) Storing and returning to the original directory (push and pop)

34) Enticing the current date into an environment variable

35) A tip for power users. Identifying the individual PC.

36) For loop and redirection quirks

37) Is it possible to traverse a directory tree with a batch?

38) It it possible to echo the redirection symbol in a batch?

39) How can I extract the file basename?

40) A batch to put user input into an environment variable

41) How can I get the last replaceable parameter given to a batch?

42) Creating an empty file if the file does not already exist

43) How can I change or remove the disk volume serial number?

44) How to pause in a batch for a preset number of seconds?

45) Where can I find a program to compile batches into COMs or EXEs?

46) How can I test whether a disk is empty or not?

47) How can I run a different batch depending on the weekday?

48) Can one put line numbers into a file with just batch commands?

49) How can I backup from the current directory files made today?

50) How can I traverse all files of a directory in a batch?

51) How can I step through a batch a command at a time to debug it?

52) How to display all files made or updated on a day or today?

53) How can I make a list of all my files and locate a certain file?

54) How can I tell if a batch is running in a Windows dosbox?

55) How can a test that there is a disk in a floppy disk drive?

56) Could you please solve this problem for me with a batch?

57) How can I make a loop that is repeated a preset number of times?

58) How can I display the contents of the memory?

59) How get today's date into a six-character environment variable?

60) How can I find and copy the files updated today in a directory?

61) How can I test in a batch whether a TSR program has been loaded?

62) Putting the current drive letter into an environment variable.

63) How can I extract the drive letter from a full file path?

64) How can I write a "SLEEP" command to pause for a certain time?

65) How can put comments into a batch file?

66) How can I echo just the word "off" in a batch file?

67) How can I extract the first two characters of a file name?

68) How can I compare two numbers with batch commands?

69) All these solutions are for wimps. Why not rather use 4DOS?

70) How can I give more than the nine parameters to a batch?

71) How can I update copy files from one directory to another?

72) How can I best clear all the files from my TEMP directory?

73) How can I check the number of parameters given to a batch?

74) How can I locate and e.g. delete all *.TMP files on a drive?

75) How can I rename all files sequentially in a directory?

76) How to search all the *.txt files on a drive for a word?

77) How can I give multiple commands on one line?

78) Is there a batch to individually zip each file in a directory?

79) A batch to substitute a string through a set of text files?

80) Where do I find a good book or WWW page on batch programming?

81) How to read a file's date and time into environment variables?


Introduction  Index  Articles  Download the text file version with samples and utilities 


Articles


1. How can I make "@echo off" MS-DOS version independent?
=========================================================

If you want to turn the echo off, and do not wish to show that line
on the screen, you can easily do this by applying
 @echo off

There is a catch, however, because this only works since MS-DOS
version 3.30. So if you want to make it general, put the following
line in your autoexec.bat file if you are using MS-DOS 3.30 or
higher
 set _echo=@
Then use the following format in your batches, which will then work
for any MS-DOS version
 %_echo%echo off
Of course, many if not most users will have a much more recent
MS-DOS version. As we know, the last released independent MS-DOS is
6.22. After that Microsoft has been pushing Windows and trying to
kill its MS-DOS despite the huge use base still left in the world.
   How does one find out which MS-DOS version one has? The version
is, of course, given by the VER command. For using this in testing
in a batch see the later item #30 "How to obtain the MS-DOS version
into an environment variable?"
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


2. Deleting all files without being prompted
============================================

One of the most Frequently Asked Questions (FAQs) about batches is
how to suppress the "Are you sure (Y/N)?" confirmation requirement
for del *.*.  Use the following:
 echo y| del *.*
If you wish to suppress the message too, use
 echo y| del *.* > nul
There is also another alternative for doing this:
 for %%f in (*.*) do del %%f
If the directory is empty you can avoid the "File not found" message
by applying
 if exist *.* echo y| del *.* > nul
Whether or not it is sensible to suppress the confirmation can be
debated, but these are the tricks anyway. Even more dangerous is
using such a trick on DELTREE or FORMAT. Do do not recommend it. In
fact it is better to disable these two commands (so that they will
require a full path, as given in 1DOSTRIK.TXT item "7. Selected
Doskey macro examples".
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


3. Is it possible to nest for loops in batch files?
===================================================

Yes, it is possible to have nested loops of a kind in batch
programming, but not directly. You have to call a second batch file.
Consider the following two batches, and try it out by calling
test.bat.

  @echo off
  rem TEST.BAT
  for %%f in (a b c d e f) do %comspec% /c test2 %%f

  @echo off
  rem TEST2.BAT
  echo.
  for %%g in (1 2 3) do echo %1%%g

   In the above "%comspec%" has been used for greater generality
across MS-DOS versions. Alternatively you could have
  @echo off
  rem TEST.BAT
  for %%f in (a b c d e f) do call test2 %%f
In TEST2.BAT the line "echo." is only for better readability of the
output.
   It is also possible to use only one batch file by letting the
first batch create the second
  @echo off
  rem TEST.BAT
  ::
  echo @echo off > test$$$2.bat
  echo echo. >> test$$$2.bat
  echo for %%%%g in (1 2 3) do echo %%1%%%%g >> test$$$2.bat
  ::
  for %%f in (a b c d e f) do call test$$$2 %%f
  if exist test$$$2.bat del test$$$2.bat
Note the need of the extra "%":s in echoing from a batch file to
another.

Another alternative is to write everything as below on a *SINGLE*
line:
  for %%f in (a b c d e f) do %comspec% /c
    for %%g in (1 2 3) do echo %%f%%g
(The wrap has been used in the text is because of the right margin.
Don't wrap your batch.). The disadvantage of this alternative is
that the echo will be on.

In the above you may wonder about the "%COMSPEC% /C" alternative to
"CALL". The comspec is and environment variable that points to the
location of the COMMAND.COM command interpreter. The /C switch tells
that the command interpreter is to exit after performing the
specified line. The /C switch must be the last switch on the command
line. The "%COMSPEC% /C" alternative is available in earlier
versions of MS-DOS than the CALL command.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


4. How can I check in a batch whether a directory exists?
=========================================================

It is sometimes useful to be able to test whether a particular
directory exists. The following test is true if the %1 directory
does not exist.
 if not exist %1\nul if not exist %1nul echo Directory %1 does not exist

However, this does not seem to work for a CD-ROM. Probably because
of the CD-ROM drivers use a slightly different directory system with
no . (dot) and .. (dot-dot). My thanks to Bjorn Svensson for
bringing this to my attention.

Further problems are caused by the Windows dosbox / MS-DOS versions
for Windows. Although this FAQ-type file has been written for
vanilla MS-DOS let's consider the alternatives that do not rely on
the \nul trick. One way of testing the existence of a directory is
trying to write a file to it, and testing if the file then exists.
Obviously this trick can't be used for read-only devices like
CD-ROMs and write protected diskettes.
  @echo off
  if "%1"=="" goto _help
  ctty nul
  echo.>%1\tmp#$#$#
  ctty con
  if exist %1\tmp#$#$# echo Directory %1\ exists
  if not exist %1\tmp#$#$# echo Directory %1\ does not exist
  if exist %1\tmp#$#$# del %1\tmp#$#$#
  goto _end
  :_help
  echo Usage %0 [DirectoryName]
  echo No backslash. Root e.g. as C:
  echo A subdirectory e.g. as C:\TMP
  :_end
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


5. Checking that a program is available at the current directory or at path
===========================================================================

When you call a program from a batch, and do not give the explicit
path to it, it is advisable to test that the program is available
either at the current directory or the default path.
  set _found=
  if exist %1 set _found=yes
  for %%d in (%path%) do if exist %%d\%1 set _found=yes
  for %%d in (%path%) do if exist %%d%1 set _found=yes
  if "%_found%"=="yes" goto _continue
  echo %1 is not at path or the current directory
  goto _out
  :_continue
  echo %1 found at path or in the current directory
  :_out
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


6. Is it possible to use subroutines and recursion in batches?
==============================================================

Yes, it is possible to use subroutines within batches. The crucial
trick is setting an environment variable (e.g. _return) to point to
a label where to return after the subroutine has been performed. For
an example see UNPACK.BAT, and BOOT.BAT, the sections :_common and
:_subru.

Likewise it is possible to use recursion to emulate subroutines in
batches. (Recursion means that a batch calls itself).
As an example see SAFEDEL.BAT and trace the effects of the line
 for %%f in (%1) do call safedel %%f recurse
Note that safedel could be replaced by %0 because the zeroth
parameter of a batch file points to itself.

Besides the material referred to in the above, below is very simple,
artificial demonstration example of using a subroutine within a
batch file.
  @echo off
  set name_=FirstName
  set return_=_label1
  goto _subru
  :_label1
  ::
  set name_=SecondName
  set return_=_label2
  goto _subru
  :_label2
  echo Done!
  goto _end
  ::
  :_subru
  echo %name_%
  goto %return_%
  ::
  :_end
  set name_=
  set return_=
Below is the same demonstration using one-level recursion. As you
see, this option is more brief, since no accounting is needed to
keep track of the return points.
  @echo off
  if "%1"=="recurse" goto _recurse
  ::
  set name_=FirstName
  call %0 recurse
  ::
  set name_=SecondName
  call %0 recurse
  ::
  echo Done!
  goto _end
  ::
  :_recurse
  echo %name_%
  ::
  :_end
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


7. How can I convert a lowercase parameter to uppercase?
========================================================

This example shows how to ensure that the parameter %1 given to the
batch is in uppercase. This utilizes the fact that MS-DOS converts
the path to uppercase. The result is stored in upcase_ and then the
original path is restored.
  set tmp_=%path%
  path=%1
  set upcase_=%path%
  path=%tmp_%
  set tmp_=

The also is another method for getting case-independent results.
This is adapted from Jeff Prosise's column in PC Computing, March
1993, pp. 216-217. If the batch below is called TEST.BAT, it makes
no difference whether you enter "TEST yes" or "TEST YES" or "TEST
yEs".
  @echo off
  if not "%1"=="" set %1=*****
  set status_=
  if "%yes%"=="*****" set status_=yes
  if "%no%"=="*****" set status_=no
  if not "%status_%"=="" echo The parameter %%1 was a %status_%
  if "%status_%"=="" echo The parameter %%1 was neither a yes nor a no
  if not "%1"=="" set %1=
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


8. Is there an easy way to append a new directory to the path?
==============================================================

This often needed trick is basically very simple. For example
to add directory %1 to path use
 path=%path%;%1
Note that you can only use this trick in a batch. It will not work
at the MS-DOS prompt because the environment variables are expanded
(%path%) only within batches.

For a full treatment with safeguards against appending non-existing
directories, or appending twice, see ADDPATH.BAT in the collection.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


9.  How can I compare if two files two files are identical?
===========================================================

It is possible in batch programming to test whether or not two files
have identical contents. This trick utilizes the external MS-DOS
programs fc.exe and find.exe. (An external MS-DOS program means, of
course, a program that comes with the standard MS-DOS releases. Most
often the MS-DOS external support files are located in a c:\dos
directory.)
  @echo off
  fc %1 %2 > tmp$$$
  type tmp$$$ | find /i "fc: no differences encountered" > diffe$$$
  if exist notsame$ del notsame$
  copy diffe$$$ notsame$ > nul
  if not exist notsame$ echo Files %1 and %2 are different
  if exist notsame$ echo Files %1 and %2 are identical
  if exist tmp$$$ del tmp$$$
  if exist notsame$ del notsame$
  if exist diffe$$$ del diffe$$$
If you think about, this idea can be used for other useful purposes,
too, because it establishes whether a given string is found in a
text file.
   The batch in the above is generic across various MS-DOS versions.
For later MS-DOS versions the batch can be simplified since FIND
returns the success of the search as an errorlevel. For more on that
aspect, type "HELP FIND".
  @echo off
  fc %1 %2 | find /i "FC: no differences encountered" > nul
  if errorlevel==2 goto _2
  if errorlevel==1 goto _1
  echo Files %1 and %2 are identical
  goto _continue
  :_1
  echo Files %1 and %2 are different
  goto _continue
  :_2
  echo Error in the FIND search
  :_continue
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


10. Writing an empty line to the screen. How is that done?
==========================================================

This is a simple, but an often needed, useful trick. Just use echo
with (for example) a point (.) right after it. No space. As you can
see, I have utilized this batch feature extensively in my batch
collection.
  @echo off
  echo Hello world
  echo.
  echo Batches are fun

 Q: A further question. I wanted to create an empty file but after
  echo.> tmp
the size of the tmp file is two bytes.

 A: Of course it is. The "echo." displays one empty line on the
screen, i.e. inserts an end of line. Thus the contents of the tmp
file will be Hex 0D 0A (ASCII 13, 10 in decimal), just as it should
in MS-DOS. For creating an empty file, please see the relevant,
separate item in this FAQ.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


11. A tip: Customizing the pause message
========================================

You can easily customize the message given by pause by giving your
own with echo and directing the pause message to nul.
to nul.
 echo Break to quit, any other key to remove the tmp directory
 pause > nul
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


12. A tip: Complicated renaming of files with for
=================================================

A considerable number of batch related questions on Usenet news seem
to relate to different kinds of file name handling. One set of these
questions relate to renaming files. Everyone knows the rudiments
like "REN OLDNAME.* NEWNAME.*" but one can conveniently utilize the
FOR statement for more complicated renaming tasks. Although this is
basically trivial, one does not necessarily come to think of it. The
FOR statement is quite useful for involved renaming of files. An
example delineates. For example I have the following files (Turbo
Pascal units for TP 4.0, 5.0, 5.5, 6.0 and 7.0). Say that I wish to
rename them to be version 35 instead of 34.
  tspa3540.zip
  tspa3550.zip
  tspa3555.zip
  tspa3560.zip
  tspa3570.zip
The following for-statement does that conveniently.
 for %f in (40 50 55 60 70) do ren tspa34%f.zip tspa35%f.zip
Naturally, renaming is not the only task that can utilize this
trick. I am sure you can readily think of others, like
  for %d in (a b) do format %d:
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


13. How can I check if the file name given included wildcards?
==============================================================

This example shows how you can easily test whether a parameter (%1)
of a batch contains wildcards.
  @echo off
  for %%f in (%1) do if "%%f"=="%1" goto _nowilds
  echo Parameter %1 contains wildcards (or is missing)
  :_nowilds
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


14. Is it possible to prevent the user from breaking the batch?
===============================================================

Yes, it is possible to prevent the user from interrupting a batch by
using the ctty command to reassign the input (and the output)
device. Here is an example (an elementary password batch requiring
inputting an e). Note the < and > redirections which are needed
while the ctty has been assigned to nul. The ASK batch enhancer is
included in the TSBAT collection. (In the later MS-DOS versions you
could as well use the CHOICE command).
  @echo off
  ctty nul
  echo Now you cannot break the batch with ^C or ^Break > con
  :_ask
  echo Use e to break > con
  ask /b /d < con
  if errorlevel==101 if not errorlevel==102 goto _out
  goto _ask
  :_out
  ctty con
  echo Back to normal. Now you can break the batch with ^C or ^Break.
Note that this trick does not prevent you from rebooting with
alt-crtl-del while the batch is running. For that you need an
external program like noboot.exe from
 103201 Mar 28 1998 ftp://garbo.uwasa.fi/pc/ts/tstsr22.zip
 TSR programs (noboot,reslock,sordino,timedown,timeup ...)
(or whichever version number is current).
The ASK.EXE usage is
 ASK [Prompt] [/b] [/d] [/l] [/t##] [/u]
                :    :    :    :      +- convert to Upper case
                :    :    :    +- Time-out parameter (0 = forever)
                :    :    +- convert to Lower case
                :    +- Direct read (no <-+ needed)
                +- Batch mode (needed only if no prompt)

This question elicits one of the most frequent false answers, i.e.
that the problem is solved by including "BREAK=OFF" in your
CONFIG.SYS file. The BREAK ON/OFF (only) toggles the extended CTRL+C
checking. For more on this see "HELP BREAK".
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


15. Can I prevent a break from bypassing the autoexec.bat?
==========================================================

You can actually prevent a quick tapping of the break from bypassing
your autoexec.bat by a variation of the trick in the item above. Put
for example
  shell=c:\command.com /p nul
in your config.sys. Before you do, make sure to have a floppy to
boot from in case something goes wrong. I first saw trick when it
was posted in the Usenet news:comp.os.msdos.programmer newsgroup by
Joseph Gil.

This is not, however, quite all there is to it. You should put
  ctty con
as the last line to your autoexec.bat. If you don't, the keyboard
will not be responding, and you must boot from the floppy you so
sensibly had prepared :-).

The /P switch makes a new permanent copy of the command interpreter.
For the details meaning of the /P switch with C:\COMMAND.COM use
"HELP COMMAND".

As you know pressing F5 before CONFIG.SYS in executed skips
CONFIG.SYS and AUTOEXEC.BAT altogether. On the other hand, it is
possible to disable the bypassing. Set in your GONFIG.SYS "SWITCHES
/K". For more see "HELP SWITCHES".
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


16) How can I extract the extension of a file name?
===================================================

It would be quite useful to be able to extract the extension of a
given file name into an environment variable. Or to be able just to
test whether there is an extension. Here is how to do that. The
batch is based on the information in PC-Magazine July 1992, Vol. 11,
No. 13, page 528. It gives the crucial information that if one
precedes the argument of a for loop with a slash (/), then the
argument is interpreted in two parts. The first part is the first
character of the argument, the second part all the rest. Neat,
indeed.
   The problem with my solution below is that it will not recognize
.* or .??? as extensions. But, of course, one can first test for
wildcards as shown in a previous item "Checking for wildcards". See
e.g. UNPACK.BAT for the utilization of this method.
     @echo off
     set exten_=%1
     :_next
     set prev_=%exten_%
     for %%f in (/%exten_%) do set exten_=%%f
     if ".%exten_%"=="%prev_%" goto _extfound
     if not "%exten_%"=="%prev_%" goto _next
     goto _noext
     :_extfound
     echo The filename %1 has an extension %exten_%
     goto _out
     :_noext
     echo The filename %1 has no extension
     :_out
     set exten_=
     set prev_=
This solution will not work after MS-DOS version 6.22, i.e. it will
not work under Windows95.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


17) Information on the quote character %
========================================

As we know %1 indicates the first parameter given to a batch. Thus
for example echo %1 echoes that parameter. But what if you want to
echo the actual string %1 instead. The % character acts as a quote
character. Thus echo %%1 will indeed be a "%1" instead of its usual
interpretation. Try the following simple test
  @echo off
  if "%1"=="" goto _out
  echo %1
  echo %%1
  :_out
See the item on "Eliminating auxiliary batches" for utilizing this
feature. A good example of utilizing this feature is given by
DELPATH.BAT. If you prepare a new batch file using a batch file
you'll need to use the % character double. A demonstration:
  @echo off
  echo>  test$$$.bat @echo off
  echo>> test$$$.bat if not "%%1"=="" echo %%1
  call test$$$ Success
  if exist test$$$.bat del test$$$.bat
Had you used only "%1", no "Success".
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


18. Eliminating auxiliary batches (making do with the main batch)
=================================================================

Quite a number of batch programming tasks require an auxiliary batch
which the primary batch has to call. Many of these cases can be
eliminated by making the batch call itself (a kind of recursion).
The auxiliary code is put in the batch itself. The trick is best
illustrated by looking at the SHOW.BAT, which provides a wild-carded
TYPE command, and would normally need an auxiliary file to type each
of the individual files. Another example is given by the SAFEDEL.BAT
batch.
   There is also an another trick for a similar purpose. The primary
batch creates and auxiliary batch or batches, which it then calls.
See DELPATH.BAT for an example of this method. Here is also a simple
demonstration listing the drives on your system. (Only from c to t,
actually because of the wrap I use here).
 @echo off
 echo @echo off> tmp$$$.bat
 echo if exist %%1:\nul echo Drive %%1: is present>> tmp$$$.bat
 for %%d in (c d e f g h i j k l m n o p q r s t) do call tmp$$$ %%d
 del tmp$$$.bat
   There was an inventive twist of this method in PC-Magazine August
1992, Vol. 11, No. 14, p. 527 for getting the volume label of a
disk. Here is my own example using the same techniques. It sets the
current directory in an environment variable getdir_. I have
utilized this technique in PUSHDIRE.BAT.
  @echo off
  echo @echo off> director.bat
  echo set getdir_=%%2>> director.bat
  echo echo %%getdir_%%>> director.bat
  dir | find "Directory"> go.bat
  call go
  if exist director.bat del director.bat
  if exist go.bat del go.bat
Incidentally, this is one example of a batch that will not work in
the Windows 95 DOS box. Since the long file names are supported you
have to use "directory.bat" instead of "director.bat" in the above!
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


19. Utilizing the subst command in paths
========================================

I use the following kind of a simple batch to make some of my
directories easy to reach. The way this simple batch is written it
avoids unnecessary errors if the substitution already has been made.
As a last measure it shows the current substitution status.
  @echo off
  if exist m:\nul echo The substitution has already been made
  if not exist m:\nul subst m: c:\math
  if not exist s:\nul subst s: c:\support
  subst
A warning. This advice is for vanilla MS-DOS only. If you have
Windows, it is highly inadvisable to use the SUBST command.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


20. How can I run a batch once a week (testing for the weekday)
===============================================================

The crucial trick is to be able to put the weekday into an
environment variable. For the full treatment see WEEKLY.BAT. The
essential trick needed is below, that is capturing the weekday into
a weekday_ environment variable. No auxiliary programs outside the
normal MS-DOS commands are needed.
  @echo off
  echo.| date | find "Current" > tmp$$$.bat
  echo set weekday_=%%3> current.bat
  call tmp$$$
  echo %weekday_%
  if "%weekday_%"=="Fri" echo Thank God it's Friday
  if exist tmp$$$.bat del tmp$$$.bat
  if exist current.bat del current.bat
  set weekday_=
In fact, if you substitute %%4 for the %%3 in the above, you'll
capture today's date. Neat, eh?
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


21. How can I test if a given file name includes the path?
==========================================================

First of all please see the earlier item "How can I extract the
extension of a file name?" because the same ideas are drawn upon.
Testing whether the file name is a bare file name like go.exe or
includes a path like r:\progs\go.exe is quite a complicated task if
one wants to allow wildcarded names like r:\progs\*.exe. This can be
done, and here is how. If one can figure this one out, one can
safely say that one has begun to understand batch files.
  @echo off
  echo @echo off> tmp$$$.bat
  echo set rest_=%%1>> tmp$$$.bat
  echo :_next>> tmp$$$.bat
  echo set prev_=%%rest_%%>> tmp$$$.bat
  echo for %%%%g in (/%%rest_%%) do set rest_=%%%%g>> tmp$$$.bat
  echo if ":%%rest_%%"=="%%prev_%%" goto _found>> tmp$$$.bat
  echo if "\%%rest_%%"=="%%prev_%%" goto _found>> tmp$$$.bat
  echo if not "%%rest_%%"=="%%prev_%%" goto _next>> tmp$$$.bat
  echo goto _nopath>> tmp$$$.bat
  echo :_found>> tmp$$$.bat
  echo set haspath_=yes>> tmp$$$.bat
  echo goto _out>> tmp$$$.bat
  echo :_nopath>> tmp$$$.bat
  echo set haspath_=no>> tmp$$$.bat
  echo :_out>> tmp$$$.bat
  echo set rest_=>> tmp$$$.bat
  echo set prev_=>> tmp$$$.bat
  for %%f in (%1) do call tmp$$$ %%f
  if "%haspath_%"=="yes" echo Filename %1 includes a path
  if "%haspath_%"=="no" echo Filename %1 does not include a path
  rem if exist tmp$$$.bat del tmp$$$.bat
  set haspath_=
Note: This will not work for MS-DOS 7 (i.e. the Windows95 version).
The above batch is based on an pre-7 MS-DOS quirk that a line like
  for %%f in (/name) do echo %%f
will return
  n
  ame
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


22. How can I display the time without having to press enter?
=============================================================

A simple trick to show the current time:
  echo.| time | find /v "new"
For capturing the time into an environment variable see
LASTBOOT.BAT and item #34.
   The /V switch means displaying all lines not containing the
specified string. This gets rid of the "Enter new time:" line.
   A more complicate way is first getting the time into an
environment variable. A trick utilized also elsewhere in this batcg
FAQ.
  @echo off
  echo @prompt set time_=$t> tmp$$$.bat
  %comspec% /c tmp$$$> tmp2$$$.bat
  call tmp2$$$
  echo %time_%
  del tmp$$$.bat
  del tmp2$$$.bat
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


23. Alternatives for testing for the errorlevel value
=====================================================

Many programs and some MS-DOS commands (like diskcomp, format and
xcopy) return an errorlevel exit code on termination. Testing for
the errorlevel is complicated by the cumulative nature of
errorlevels. Thus if you wish to test if the errorlevel was
(exactly) 2, you must use
 if errorlevel==2 if not errorlevel==3 echo Errorlevel 2
Another alternative is utilizing the for command:
 for %%e in (0 1 2 3 4 5 6 7) do if errorlevel==%%e set _errlev=%%e
 if "%_errlev%"=="2" echo Errorlevel 2
Alternatively, and more generally
 for %%e in (0 1 2 3 4 5 6 7) do if errorlevel==%%e set _errlev=%%e
 if "%_errlev%"=="2" echo Errorlevel %_errlev%
A convenient trick in more complicated batches is using the goto
command:
  for %%e in (0 1 2) do if errorlevel==%%e goto _label%%e
  goto _out
  :_label0
  echo Errorlevel 0
  :_label1
  echo Errorlevel 1
  :_label2
  echo Errorlevel 2
  :_out
See BOOT.BAT for actual usage of this technique.
   The order in which there errorlevels are given is significant,
since all the errorlevels up to the one returned will be on.
Consider the following demonstration
  @echo off
  find "hello" con > nul
  if errorlevel==2 echo errorlevel 2  % error in search %
  if errorlevel==1 echo errorlevel 1  % no match found %
  if errorlevel==0 echo errorlevel 0  % match found %
If you type
  peekaboo
  ^Z
you'll get *both*
  errorlevel 1
  errorlevel 0
If you type
  hello
  ^Z
then you'll get just
  errorlevel 0

Speaking of errorlevels, some novice batch users occasionally ask
for the general list of the meanings of the errorlevel values. This
question is based on a failure to grasp how errorlevels are created.
Batch files can only test their values. It is the executable
programs that can return errorlevel values. What the particular
values are, which an executable program returns, is totally
dependent on the individual program. Some programs may be able to
return a lot of different values, some none (or rather return zero
errorlevel). Perhaps this misunderstanding is based on the fact that
MS-DOS includes a number of programs, such as CHOICE.COM, FIND.EXE
and XCOPY.EXE which return errorlevels. For example MS-DOS version
6.22 XCOPY.EXE can signal with six different errorlevel values (0 to
5) depending on the outcome. For those values see "HELP XCOPY" and
select "Notes".
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


24. About redirecting a batch file's output
===========================================

Output from within a batch file is easily redirected. Consider a
batch file example.bat with the following contents
  @echo This is a redirection test> test
Running "example" will produce a file "test" with
  This is a redirection test
The line has an eoln (end of line: ascii 13 + 10) at the end.
Note that it often is advisable not to leave any blank in front of
the > redirection operator.

Redirecting the output that a batch produces, is more complicated.
Consider a batch file example2.bat with the following contents
  @echo This is another redirection test
Running
  example2 > test
will produce an empty "test" file, while the text is echoed on the
standard output. To redirect the output, you need to drive the batch
through the command interpreter command.com like this (provided that
command.com is at path or in the current directory).
  command /c example2 > test
This will redirect the text to the "test" file.

There is another quirk of redirection in MS-DOS batch programming
best demonstrated by an example:
  @echo off
  rem This line will create an empty tmp.$$ file > tmp.$$
  :: This line will not create an empty tmp.$$$ file > tmp.$$$
  rem This line will cause problems: Press 
  :: This line will not cause problems: Press 
As explained in PC Magazine Vol 12, Number 9, November 9, 1993, the
reason is that the :: is taken as a label and not processed while
the rem basically is an MS-DOS command that will be processed. The
processing will start from the redirection at the end. This is the
the also reason why redirection and the MS-DOS FOR command will
cause problems. (See the entry "For loop and redirection quirks".)
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


25. How can I test if my batch has sufficient environment space?
================================================================

If your batch utilizes environment variables there is a possibility
that you run out of environment space. If you get an "Out of
environment space" message the well-known trick to increase your
environment space by using shell configuration in config.sys:
  Example: shell=c:\bin\command.com c:\bin /e:1024 /p

A perhaps less-known trick is that you can test in advance if your
batch will run out of environment space. Below is an example showing
you how to test if you have an additional 32 bytes of environment
space still available for your batch:
  @echo off
  set test_=12345678901234567890123456789012
  if "%test_%"=="12345678901234567890123456789012" goto _yes
  echo Insufficient environment space
  goto _out
  :_yes
  echo Sufficient environment space
  set test_=
  rem Whatever you wish to do
  :_out
To test more extensively you can use
  @echo off
  for %%f in (a b c d e f g h i j k l m n o p q r s t u v x y z)
    do set %%f=12345678901234567890123456789012345678901234567890
  set
  echo "%z%"
  if "%z%"=="12345678901234567890123456789012345678901234567890" goto _yes
  echo Insufficient environment space
  goto _out
  :_yes
  echo Sufficient environment space
  :_out
Note! The "for" and "do" should  go on the same line but have been
wrapped for legibility because of the right margin.
   If you want to know what your initial environment size is, you
can use a program like SYSINFO.EXE from
 148195 May 17 1998 ftp://garbo.uwasa.fi/pc/ts/tsutil44.zip
 Timo's 1st utility set (sysinfo,dirw,dtetimal,timelog,...)
or whatever is the current version number of the package.

If you have a batch where getting it right is critical, it is
advisable to test for the environment space sufficiency. The sample
batch below describes the principle
  @echo off
  set critical_=whatever
  if not "%critical_%"=="whatever" goto _nospace
  echo Rest of the batch, no problem
  goto _out
  ::
  :_nospace
  echo Warning: Out of environment space, batch terminated
  ::
  :_out
  set critical_=
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


26. Is there a simple trick to "disable" or hide a drive?
=========================================================

It you wish temporarily disable a drive use the subst command for
example as follows
  @echo off
  md c:\none
  subst d: c:\none
To enable it again use
  @echo off
  subst d: /d
  rd c:\none
A warning. This advice is for vanilla MS-DOS only. If you have
Windows it is highly inadvisable to use the SUBST command.
   In ftp://garbo.uwasa.fi/pc/ts/ts5dos11.zip there is program
DRIVEOFF.EXE which can be used to disable/enable a drive. It
requires at least MS-DOS version 5.0.
   Directories are much easier. You can hide a directory with the
standard ATTRIB +H command, just like any ordinary file.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


27. How can I send an escape sequence to the printer?
=====================================================

Here is a truly trivial trick. You cannot send escape sequences to
the printer directory from the command line, but it is quite easy to
do that from a simple batch file:
  @echo ESC%1> prn
where you have to replace the ESC by the true escape character using
your preferred editor. One snag with this methods is that it imposes
a linefeed.
   In this connection it is often also asked how one does enter the
escape character in a text editor. This, of course, depends on the
editor you are using. Nevertheless, with most editors you can either
enter 27 from the numerical part of the keyboard while holding down
the alt key (ALT-27). Furthermore, the combination of CTRL-P ESC is
a rather common convention in many text editors. If you are using
Windows 3.1x, one additional option is to use Character Map, located
in Accessories, to first copy the escape character to the clipboard.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


28. Is it possible to create a random string in a batch?
========================================================

I was asked on the UseNet news how to create a random string. My
reply. Please study the following example and expand on it
  @echo off
  echo 10 randomize(val(mid$(time$,7,2))) > tmp.bas
  echo 20 open "tmp2.bat" for output as #1 >> tmp.bas
  echo 30 x$ = mid$(str$(int(rnd*10000)),2) >> tmp.bas
  echo 40 print #1,"@set random_=";x$ >> tmp.bas
  echo 50 close #2 >> tmp.bas
  echo 60 system >> tmp.bas
  gwbasic tmp.bas
  call tmp2
  del tmp.bas
  del tmp2.bat
  set
Alternatively, depending on your MS-DOS version, you might have not
have GWBASIC but QBASIC. In that case use replace the eighth line
with "qbasic /run tmp.bas".
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


29. Is it possible in a batch to find out the length of a string?
=================================================================

The task of finding out the length of a string was tackled in PC
Magazine January 26, 1993 issue. The solution is my own and more
general, but naturally it has similar ingredients to the PC
Magazine's.
  @echo off
  set test_=Testing the length of a string
  echo %test_% > len$&$&$
  dir len$&$&$ | find "LEN$&$&$" > go$$$.bat
  echo @echo off> len$&$&$.bat
  echo set length_=%%1>> len$&$&$.bat
  call go$$$
  echo The length is %length_% bytes
  del len$&$&$
  del len$&$&$.bat
  del go$$$.bat
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


30. How to obtain the MS-DOS version into an environment variable?
==================================================================

Here is the code how to do it.
  @echo off
  ver > go$$$.bat
  echo @echo off> ms-dos.bat
  echo set version_=%%2>> ms-dos.bat
  call go$$$
  echo Your MS-DOS version is %version_%
  del go$$$.bat
  del ms-dos.bat

MS-DOS 5.0 version introduced many enhancements (like the loadhigh
command, etc) and additions to the command switches (like /B and /S
to the DIR command). Therefore it is useful to be able to test
whether the batch is being run on a system that is at least MS-DOS
5.0. Below is one option for vanilla MS-DOS versions. Version 7 is
not included, because it is a non-independent Windows95 addition.
  rem Establish whether MS-DOS version 5.0 or later is being used
  set isver50_=
  ver | find "5.0" > tmpfind.$$$
  ver | find "6.0" >> tmpfind.$$$
  ver | find "6.2" >> tmpfind.$$$
  copy tmpfind.$$$ tmpfind1.$$$ > nul
  del tmpfind.$$$
  if exist tmpfind1.$$$ set isver50_=yes
  if exist tmpfind1.$$$ del tmpfind1.$$$
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


31. How can I find out the number of regular files on a drive?
==============================================================

Try
  @echo off
  attrib /s c:\*.* | find /c "\"
The directories will not be (mis)counted as files as would with the
dir command. Besides the dir command is not recursive until MS-DOS
version 5.0.
   Note that if you do this for the same drive where you reside,
you'll get one too many in the count because of the "|" pipe.
   The /S switch in ATTRIB makes the command traverse also
subdirectories. The /C switch in FIND gives the number of the
matches found.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


32. How can I use a batch to augment line numbers to my text file?
==================================================================

Occasionally it might be useful to put line number to a text file.
Here is an example how to do it with MS-DOS commands only
  @echo off
  type YourFile.txt | find /v /n "&$&$&$123" > YourNew.txt
The parameter &$&$&$123 stands for an improbable string, since find
/v means displaying all the lines not containing it. The switch /n
means numbering the lines.
   Here is an interesting, but probably a fairly useless little
twist:
  @echo off
  dir /b | find /v /n "&$&$&$123" | find "[20]"
It tells you which is the twentieth entry in a directory.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


33. Storing and returning to the original directory (push and pop)
==================================================================

There are several methods for (non-resident) pushing and popping the
directory by batch file techniques. In other words storing the
current directory, changing the directory in between, and then
returning to the starting directory. PUSHDIRE.BAT and POPDIRE.BAT
give one method where the current drive and directory are stored in
environment variables. The second method, displayed below, is a
direct adaptation from Jeff Prosise's column in PC Computing, March
1993, pp. 216-217. Later the trick was presented again in PC
Magazine June 14, 1994, Vol. 13, No. 11, p. 357. The method is a
very clever utilization of the prompt system. An example
illustrates.
  @echo off
  echo @prompt cd $p$_$n:> c:\setback.bat
  %comspec% /c c:\setback> c:\goback.bat
  ::
  rem Change the drive and directory
  c:
  cd \dos
  echo The current directory is
  cd
  rem Do whatever you wish to do there
  pause
  ::
  rem Go back to the original drive and directory
  call c:\goback
  echo Now back in the original directory
  cd
  ::
  rem cleanup
  if exist c:\setback.bat del c:\setback.bat
  if exist c:\goback.bat del c:\goback.bat

 A2: Tom Lavedas posted in news:alt.msdos.batch "I think the best
way to get the current directory's name into the environment is to
use something like this ...
  @echo off
   echo @prompt set CurrentLoc=$p$_ > {tempA}.bat
   %comspec% /e:2048 /c {tempA}.bat > {tempB}.bat
   for %%v in ({tempB}.bat del) do call %%v {temp?}.bat
This approach extracts the information from the PROMPT command's
output, making use of that statement's dollar sign equivalences."
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


34. Enticing the current date into an environment variable
==========================================================

Like in the item "Storing and returning to the original directory"
there are more than one way of doing this. One method is indicated
in the item "How to run a batch once a week". The other (again)
utilizes the prompt:
  @echo off
  echo @prompt set date_=$d> c:\tmp$$$.bat
  %comspec% /c c:\tmp$$$> c:\tmp2$$$.bat
  call c:\tmp2$$$
  echo %date_%
  del c:\tmp$$$.bat
  del c:\tmp2$$$.bat
If you look at your MS-DOS manual for the prompt special $ codes
(like $d) that you can use in the prompt, you'll see that this
method opens quite a number of possibilities of putting information
into environment variables. Exercise: Put the current weekday into
an environment variable. Hint: Apply $d and $h.

A second method is given below. In this alternative the date is
stored in the %date_% environment variable in the eight-character
format. It also gets the current time.
  @echo off
  ::
  rem Create a temporary batch file to set the date
  echo @echo off> date$$$$.bat
  echo set date_=%%3>> date$$$$.bat
  echo set time_=%%4>> date$$$$.bat
  ::
  rem Create another batch which executes the first
  dir date$$$$.bat | find "DATE$$$" > tmp$$$.bat
  call tmp$$$
  ::
  rem Delete the temporary batch files
  if exist tmp$$$.bat del tmp$$$.bat
  if exist date$$$$.bat del date$$$$.bat
  ::
  rem Test it
  echo %date_%
  echo %time_%

For a third method that puts the date into the %date_% environment
variable see e.g. the item "How can I backup from the current
directory files made today?" of this batch FAQ collection. It
produces the ten-character format.

Let's return to the first method. Batch savant Tom Lavedas often
uses the following kind of style.
  @echo off
  echo @prompt set Date=$d$_set Time=$t$h$h$h> {a}.bat
  %comspec% /e:2048 /c {a}.bat > {b}.bat
  for %%v in ({b}.bat del) do call %%v {?}.bat
  echo The date is %Date% and the time is %Time%
Let's study closer the logic of this batch. There is much to learn
from the details.

  1) @echo off
     - turns off echoing the commands on the screen
  2) echo @prompt set Date=$d$_set Time=$t$h$h$h> {a}.bat
     - creates auxiliary batch {a}.bat and puts there
       @prompt set Date=$d$_set Time=$t$h$h$h
     - $d displays the current date in the prompt
     - $_ enters a linefeed in between
     - $t displays the current time in the prompt
     - $h$h$h deletes the last three characters,in this case the
              superfluous hundreds of the second)
  3) %comspec% /e:2048 /c {a}.bat > {b}.bat
     - runs {a} and put the results into another auxiliary batch
       {b}.bat whose contents will be e.g.
         set Date=Sat 11/07/1998
         set Time=14:07:03
     - /e:2048 reserves (usually) enough environment space
     - /c tells the command interpreter to exit after performing
          the task. This avoids multiple shells.
  4) for %%v in ({b}.bat del) do call %%v {?}.bat
     - this is "shorthand" for
         call {b}.bat
         del {?}.bat  %which deletes both {a}.bat and {b}.bat%
  5) echo The date is %Date% and the time is %Time%
     - displays the result

Please also see the related, further refined later item "How get
today's date into a six-character environment variable?".
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


35. A tip for power users. Identifying the individual PC.
=========================================================

In cases of some batches it is useful to identify the PC the batch
is run on. For example I have several different PCs myself and
occasionally I need to differentiate between them. The solution is
really trivial. Set an environment variable in the autoexec.bat to
designate the PC. I use a variable pcid_ for this purpose. An (old)
outline batch illustrates.
  @echo off
  if "%pcid_%"=="" goto _none
  goto %pcid_%
  :dell
  echo Dell 325N laptop, do whatever
  goto _out
  :trifu
  echo Trifunic 386 desktop, do whatever
  goto _out
  :karvi
  echo "Garfunkel" Pinus 486 desktop, do whatever
  goto _out
  :_none
  echo PC not identified, do whatever
  :_out
For example in the autoexec.bat of my DELL 325N laptop I have
  set pcid_=dell
You'll see this identification trick used e.g. in the BOOT.BAT batch
of the collection at hand.

Another, similar trick I employ is standardizing the ram disk
reference by applying in my AUTOEXEC.BAT e.g.
  set ram=m
This I can always refer in my batches as %ram% to the ram disk
letter irrespective of which of my PCs I am using. You'll see this
trick used in some of the individual batch files of this collection.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


36. For loop and redirection quirks
===================================

A question from the Usenet newsgroups news:comp.os.msdos.misc and
news:comp.os.msdos.programmer:
> I am using DOS 5.0 and I have the following line in my batch file:
> for %%f in (a b c d) do if exist %%f echo put %%f >> tmpfile
> where a,b,c,d are some filenames.
>
> What I expect it to do is to echo the lines
>  put a
>  put b
>  put c
>  put d
> into the file tmpfile.
>
> But what happen is after the "put a" is written to tmpfile, the rest
> of the lines will just echo to the screen, look like that the
> redirection is not working.
>
> If I take away the "if exist" everything is working fine.  I found
> out every time when I use a conditional statement with redirection,
> it will only redirect the first time, the rest will echo to the
> screen.
>
> Is it the for loop cannot be mixed with the conditional statement
> and the redirection?

Yes, it can be mixed, but not so simply in this case. Use the
following batch
  @echo off
  del tmpfile
  for %%f in (a b c d) do if exist %%f call auxil %%f
where auxil.bat contains
  @echo off
  echo put %1>> tmpfile
I'll be darned if I know why :-).

In fact it is possible to do this with a single batch by employing
the following method described in an earlier item
  @echo off
  echo @prompt echo put %%%%1$g$g tmpfile> tmp$$$.bat
  %comspec% /c tmp$$$> auxil.bat
  if exist tmpfile del tmpfile
  for %%f in (a b c d) do if exist %%f call auxil %%f
  del tmp$$$.bat
  del auxil.bat
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


37. Is it possible to traverse a directory tree with a batch?
=============================================================

Traversing it straight up is relatively easy as can be seen from
this example.
  @echo off
  :_loop
  dir/w
  if not exist ..\nul goto _out
  cd ..
  goto _loop
  :_out
Going recursively down through a directory and its subdirectories is
very complicated. Yet it can be done if you have MS-DOS 5.00 or
beyond. The SWEEP.BAT batch accompanying tsbat*.zip demonstrates
how. The method is, however, too difficult to be of real practical
importance. It is getter to use an auxiliary program for sweeping,
like TARGET.EXE ftp://garbo.uwasa.fi/pc/filefind/target15.zip or
SWEEP.COM from ftp://garbo.uwasa.fi/pc/pcmagvol/vol4n24.zip.
Especially TARGET.EXE is a very versatile tool.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


38. It it possible to echo the redirection symbol in a batch?
=============================================================

In certain situations would be useful to be able echo the
redirection symbol rather than have its perform its redirection
function. For example your batch file might have a help line like
this
  echo The line to customize is "echo dir/w %%%%3\%%2 >> %%new_%%"
As you see the double quotes pre-empt the redirection. If you left
them out, the line would result create a file %NEW_% containing
"The line to customize is echo dir/w %%3\%2".
   Contrary to Unix, \ cannot be used to cover the special meaning
of a symbol. As explained in the item "The quote character %" the %
sign, can as is demonstrated above by the %% pairs. But %> does not
take precedence over the redirection.
   Tom Lavedas posted a useful example in news:alt.msdos.batch which
shows additional trick in the the echoing to the screen. The
solution goes like this:
  @echo off
  echo "^HThis is a pair of greater than signs >>"^H.
In the above the ^H means the backspace character which you can
input e.g. in MS-DOS Edit by entering ctrl-P H . An additional
aspect of this solution is that the last ^H must be followed by at
least one character. Otherwise the last " will be sent to the
console.

 Q2: I want to send the character | to a batch to form a batch file.
For instance when I try the following
     echo dir /w /p | find "Vol" >>file.bat
I get a file.bat file that contains nothing. How can I solve this?

 A2: This problem can be solved by using QBASIC which comes with
e.g. MS-DOS version 6.22. Below is the batch that does what is being
asked for. The crucial trick is to use variables for the characters
which batches cannot redirect. Below b$ contains |, i.e. the ASCII
character 124. (q$ contains the quote " character.)
  @echo off
  >  tmp$$$.bas echo LET q$ = CHR$(34)
  >> tmp$$$.bas echo LET b$ = CHR$(124)
  >> tmp$$$.bas echo OPEN "file.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "@echo off"
  >> tmp$$$.bas echo PRINT #1, "dir /w "; b$; " find "; q$; "Volume"; q$
  >> tmp$$$.bas echo CLOSE #1
  >> tmp$$$.bas echo SYSTEM
  qbasic /run tmp$$$.bas
  del tmp$$$.bas
P.S. The /w switch and especially the /p switch in the question are
superfluous.

There also is a prompt-base solution as pointed out by Tom Lavedas:
"It can also be solved using the characteristics of the PROMPT
command, specifically the dollar sign substitution character '$B',
something like this ...
  echo @prompt dir /w /p $b find "Vol" > {t}.bat
  %comspec$ /e:2048 /c {t}.bat >> file.bat
  del {t}.bat
BTW, I usually can find a way around needing such a construction,
often with less programming overhead."
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


39. How can I extract the file basename?
========================================

Occasionally one needs to get the file name without the extension.
Just like getting the extension from a file name using the "for %%f
in (/%exten_%)" trick, even this can be done with batch commands
only. The batch code for getting the basename has been presented by
Neil Rubenking in PC Magazine April 26, 1994, Vol. 13, No. 8, pp.
275-276. But enough is enough even with batch tricks. The logic is
getting overly complicated. One has to draw the line somewhere, stop
kidding oneself, and start using batch enhancers (external programs
to help out). I think here the limit has been reached. Hence I have
included "basename" and "basepath" programs, which you can use to
create the enhancers. They return the relevant information into an
environment variable with that name.
   When you come to think of it. From one viewpoint, what else than
batch enhancers are all the external MS-DOS commands (usually) in
your C:\DOS directory?
   Using basename and basepath is very easy. Below is an example
       @echo off
       basename r:\cmand\command.com
       basepath r:\cmand\command.com
       echo %basename%
       echo %basepath%
You can discard the environment variable simply by applying (note
the two alternatives):
       set basename=
       basepath
There is also a "basexten" batch enhancer in the /pc/ts/tsbat*.zip
collection.
   A batch-only solution is presented below. It owes heavily to a
posting by Ted Davis in news:alt.msdos.batch.
  @echo off
  ::
  rem Instructions
  if "%1"=="" goto _usage
  ::
  rem Create an auxiliary directory
  mkdir tmpaux$$
  ::
  rem Create an empty auxiliary file
  rem > tmpaux$$\%1
  ::
  rem Go to the auxiliary directory
  cd tmpaux$$
  ::
  rem Rename the file without extension (this is the trick!)
  ren %1 *.
  ::
  rem Get the new file name into an environment variable
  for %%f in (*) do set basename=%%f
  ::
  rem Let's test it
  echo The basename is %basename%
  ::
  rem Back to the original directory
  cd ..
  ::
  rem Delete the auxiliary file
  echo.| del tmpaux$$\*
  ::
  rem Delete the auxiliary directory
  rmdir tmpaux$$
  ::
  rem Delete the environment variable
  set basename=
  ::
  goto _end
  ::
  :_usage
  echo Usage: %0 [FileNameWithExtension]
  :_end
Another batch-only alternative would be to utilize the BASIC
interpreters that come with MS-DOS.
  @echo off
  ::
  :: If no parameter is given to the batch, show its proper usage
  if "%1"=="" goto _help
  ::
  :: Prepare a QBASIC program to extract the base from a filename
  :: Handle different file name types like NAME.DAT NAME and .DAT
  echo LET a$="%1" > tmp$$$.bas
  echo LET p = INSTR(1, a$, ".") - 1 >> tmp$$$.bas
  :: Case of only extension, no basename
  echo IF p = 0 THEN LET a$ = "" >> tmp$$$.bas
  :: Other cases
  echo IF NOT (p=-1) AND NOT (p=0) THEN LET a$ = MID$(a$, 1, p) >> tmp$$$.bas
  echo OPEN "tmp###.bat" FOR OUTPUT AS #1 >> tmp$$$.bas
  echo PRINT #1, "@echo off" >> tmp$$$.bas
  echo PRINT #1, "set basenam_=" + a$ >> tmp$$$.bas
  echo SYSTEM >> tmp$$$.bas
  qbasic /run tmp$$$.bas
  ::
  :: Call the batch created by the QBASIC program
  call tmp###.bat
  ::
  :: Demonstrate that the result is in the basenam_ environment variable
  if not "%basenam_%"=="" echo The basename of %1 is %basenam_%
  if "%basenam_%"=="" echo The basename of %1 is empty
  goto _end
  ::
  :_help
  echo Usage %0 [FullFileName]
  ::
  :: Cleanup
  :_end
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  set basenam_=
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


40. A batch to put user input into an environment variable
==========================================================

This definitely must be the neatest batch programming trick I have
ever seen. It is an adaptation of the batch published in Neil J.
Rubenking's User-to-User column in PC Magazine June 27, 1995, Vol.
14, No. 12, pp. 247-248. It is based on an idea by Tom Lavedas. It
will remedy the biggest (alleged) flaw in MS-DOS batch programming,
that is getting user input without any external programs. My
adaptation puts a simple word input into the INPUT_ environment
variable. The original inputs a whole sentence, but it is more
complicated. A single word (or a single letter) input is what is
usually sufficient in batch programming. The essence of the trick,
of you want to study it carefully to understand it, is in the fact
that the time command outputs the word "Enter" which features as an
auxiliary batch to be run by the SETINPUT.BAT below. An MS-DOS
version 3.3 or later is required.
  @echo off
  rem INPUT.BAT
  echo This will copy your input to the environment variable INPUT_
  echo Give your input:
  fc con nul /lb1 /n | time | find "    1:  "> setinput.bat
  echo @echo off> enter.bat
  echo set input_=%%4>> enter.bat
  call setinput
  del setinput.bat
  del enter.bat
  echo The value of INPUT_=%input_%
The /LB switch in the above with value 1 sets to one the number of
lines for the internal line buffer. The /N switch "displays the line
numbers during an ASCII comparison".
   For more on this approach see Tom's WWW page "Input in a Running
Batch File" http://www.deltaelectronics.com/tglbatch/input.htm.
   This is also a suitable spot to show the usage of the MS-DOS
CHOICE.COM input command with the following example. Note that the
order of the errorlevel tests is significant and should be retained
in the order used below.
  @echo off
  choice /c:ync /t:c,10 "Respond within 10 seconds (else C is assumed) "
  if errorlevel 3 goto _cancel
  if errorlevel 2 goto _no
  if errorlevel 1 goto _yes
  if errorlevel 0 goto _break
  echo Error! This should not happen.
  goto _end
  :_break
  echo Break was pressed
  goto _end
  :_yes
  echo Y was pressed
  goto _end
  :_no
  echo N was pressed
  goto _end
  :_cancel
  echo C was pressed, or no response within 10 seconds
  :_end
For an explanation of the CHOICE.COM switches apply "HELP CHOICE" if
you have MS-DOS 6.22.

 A2: It is instructive to note that batches often can be improved
since there is some hitch. In this case Larry Weiss observed that
"If the user enters only the Return-key, then the bat file will
reset the system time to 1:00 am. There is no warning about this
unfortunate side-effect. That bat file can be re-written to use
'date' instead of 'time' (replacing the reference to %%4 with %%5)
as:
  @echo off
  rem INPUT.BAT
  echo This will copy your input to the environment variable INPUT_
  echo Give your input:
  fc con nul /lb1 /n | date | find "    1:  "> setinput.bat
  echo @echo off> enter.bat
  echo set input_=%%5>> enter.bat
  call setinput
  del setinput.bat
  del enter.bat
  echo The value of INPUT_=%input_%
With those changes, there is no unexpected disturbance of either the
date nor time when no input is provided."

 A3: Another, easier approach to this problem is using a QBASIC
solution. QBASIC comes with e.g. MS-DOS version 6.22.
  @echo off
  ::
  :: Build a QBASIC program to a file tmp$$$.bas
  >  tmp$$$.bas echo PRINT "Give your input";
  >> tmp$$$.bas echo INPUT a$
  >> tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "@echo off"
  >> tmp$$$.bas echo PRINT #1, "set input=";a$
  >> tmp$$$.bas echo CLOSE #1
  >> tmp$$$.bas echo SYSTEM
  ::
  :: Run the QBASIC program prepared in the above
  qbasic /run tmp$$$.bas
  ::
  :: Call the tmp###.bat batch created by the tmp$$$.bas QBASIC program
  call tmp###.bat
  ::
  :: Delete the auxiliary files
  del tmp$$$.bas
  del tmp###.bat
  ::
  :: Test the result
  echo Your input was %input%
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


41. How can I get the last replaceable parameter given to a batch?
==================================================================

As we know, batch files can use the so-called replaceable parameters
from %0 to %9. It is easy to get the first parameter in a batch
call. It is %1. (%0 gives the batch name). But what about getting
the last parameter when you do not know in advance how many
parameters the call has. Below is the code. It puts the last
parameter in the environment variable NF_.
  @echo off
  set nf_=
  :_loop
    if "%1"=="" goto _end
    set nf_=%1
    shift
    goto _loop
  :_end
  rem Let's test the result
  if not "%nf_%"=="" echo %nf_%
  if "%nf_%"=="" echo No parameters were given to the batch
Note a catch. After you apply the above, you no longer can access
the original parameters. If you need them later in the batch, you
have to store them at the outset of the batch file, e.g. like this
  set bname_=%0
  set a_=%1
  set b_=%2
  set c_=%3
John Savage points out that the code for getting the last parameter
can be made simpler:
  @echo off
  :_loop
  shift
  if not "%1"=="" goto _loop
  echo last parameter is "%0"
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


42. Creating an empty file if the file does not already exist
=============================================================

@echo off
if exist testfile goto _nocreate    %Don't destroy an existing file%
rem > testfile
:_nocreate
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


43. How can I change or remove the disk volume serial number?
=============================================================

Since version 4.0 the disk serial number was added to MS-DOS. When
you format a disk is it given a number like 4132-1DFF. It is
possible to change that information with an innovative batch file
alone. The batch by Bruce W. Shumway can be found in the PC Magazine
April 23, 1996, Vol. 15 No. 8, pp. 221-222. There also is a program
SETSER.EXE "Set the disk's serial number" by yours truly in the
ftp://garbo.uwasa.fi/pc/ts/ts5dos11.zip collection.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


44. How to pause in a batch for a preset number of seconds?
===========================================================

You can use the MS-DOS CHOICE.COM command for the purpose as the
example below demonstrates
  @echo off
  echo Testing a delay, starting at ...
  echo.| time | find /v "new"
  choice /c:. /t:.,5 /n Pausing for five seconds
  echo ending at ...
  echo.| time | find /v "new"
The choice command was introduced with MS-DOS 6. If you have an
earlier MS-DOS version you can use my similar CHOOSE.EXE from
ftp://garbo.uwasa.fi/pc/ts/tsutlf15.zip.
   For pauses longer than 99 seconds see the item #64. For better
understanding the CHOICE parameter values, see the end of item #40.

Tom Lavedas points out that if one uses
  type nul | choice /c:. /t:.,5 /n Pausing for five seconds
"The piping of the output from the TYPE command into CHOICE acts to
defeat keyboard entry for the wait period."

Also see the later item "How can I write a "SLEEP" command to pause
for a certain time?" for more on this question.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


45. Where can I find a program to compile batches into COMs or EXEs?
====================================================================

Since this question is so frequently asked I'll include an answer
into my 1batfaq.txt information file. From Garbo program archive's
MS-DOS index file ftp://garbo.uwasa.fi/pc/INDEX.ZIP we can readily
locate the following files. Personally, I am dubious about batch
compilers and their complications. In my opinion, if one wants
distribute executables, it is much better to use a genuine
programming language like Turbo Pascal or C. I prefer batches in
their regular source format.

 37419 Aug 10 1991 ftp://garbo.uwasa.fi/pc/pcmagutl/bat2ex15.zip
 bat2ex15.zip Compile batch files to be executables, PC-Mag update

 51299 Oct 31 1994 ftp://garbo.uwasa.fi/pc/batchutil/tbt324.zip
 tbt324.zip TurboBAT Batch File Compiler, Foley Hi-Tech Systems
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


46. How can I test whether a disk is empty or not?
==================================================

This question is best answered by an annotated batch source:

  @echo off
  rem Provide help if no parameter is given.
  if "%1"=="" goto _usage

  rem Check that the input syntax was acceptable.
  for %%f in (a b A B) do if "%1"=="%%f" goto _label1
  goto _usage

  rem See if "bytes free" appears in the directory listing as it will
  rem if and only if there are files in the directory.
  :_label1
  dir %1:\ /s | find "bytes free" > found.$$$

  rem If "bytes free" was not found found.$$$ file will be empty.
  rem An empty file will not be copied.
  copy found.$$$ notempty.$$$ > nul

  rem If found.$$$ was empty is was not copied, use this fact to test.
  if exist notempty.$$$ echo Disk %1: is not empty
  if not exist notempty.$$$ echo Disk %1: is empty

  rem Delete the auxiliary files.
  if exist found.$$$ del found.$$$
  if exist notempty.$$$ del notempty.$$$
  goto _out

  :_usage
  echo Usage: %0 [DriveLetter]
  echo e.g. %0 A
  echo Put no colon (:) after the DriveLetter!

  :_out

The volume where you drive this from must not be write protected.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


47. How can I run a different batch depending on the weekday?
=============================================================

  @echo off
  ::
  rem Let's take care of everything by a single batch file.
  rem First prepare a batch for each day. For brevity let's prepare
  rem them for Monday and Tuesday days only.
  ::
  echo echo It is Monday today and whatever else you may wish to do>mon.bat
  echo echo It is Tuesday today and whatever else you may wish to do>tue.bat
  ::
  rem The date command produces output like
  rem Current date is Tue 27/08/1996
  rem Enter new date (dd-mm-yy):
  ::
  rem Utilize this fact by making a batch file tmp$$$.bat which in turn
  rem runs the batch which is the third parameter (%3) of current.bat
  rem (Tue.bat in the above).
  echo.| date | find "Current">tmp$$$.bat
  echo call %%3>current.bat
  call tmp$$$.bat
  ::
  rem Let's delete the tmp$$$.bat and current.bat files.
  if exist current.bat del current.bat
  if exist tmp$$$.bat del tmp$$$.bat
  ::
  rem Since this was only a test, let's delete all the daily files, too.
  if exist mon.bat del mon.bat
  if exist tue.bat del tue.bat
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


48. Can one put line numbers into a file with just batch commands?
==================================================================

The essence of this item is from postings in news:alt.msdos.batch
by John Savage. The trick is
 FC /N nul file.txt > file2.txt
The number of lines is limited to a hundred lines. You can increase
that to a maximum of 222 lines using
 FC /N /LB222 nul file.txt
As you see, there is some redundancy in this batch FAQ, since there
are so many items. This question was already tackled in item #32 but
using a different (a FIND) method.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


49. How can I backup from the current directory files made today?
=================================================================

Here is the trick using XCOPY tested on a PC running MS-DOS 5.0.
  @echo off
  rem Get the date into an environment variable
  echo.| date | find "Current" > tmp$$$.bat
  echo set date_=%%4> current.bat
  call tmp$$$
  if exist tmp$$$.bat del tmp$$$.bat
  if exist current.bat del current.bat
  ::
  rem Copy the files created or updated today
  xcopy *.* a:\ /D:%date_% /P /V
  if errorlevel 0 goto _out
  echo An XCOPY error has occurred
  ::
  :_out
  set date_=
The country-dependent XCOPY parameter /D:date copies files modified
on or after the given date. The /P prompts for confirmation. The /V
parameter sets copy verification on.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


50. How can I traverse all files of a directory in a batch?
===========================================================

See REPEAT.BAT of my TSBAT*.ZIP batch files collection.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


51. How can I step through a batch a command at a time to debug it?
===================================================================

This question is answered by MS-DOS "HELP COMMAND". Take a look. The
essence of the method is this: "command /y /c mybatch.bat". This
lets you traverse your batch one command at a time. Another trick is
to use REM and GOTO commands to help locate when the error occurs
and when not. It has the advantage of letting you choose the parts,
which you wish to concentrate on. Yet another method is to place
PAUSE commands near the problem spots to identify which line causes
the error.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


52. How to display all files made or updated on a day or today?
===============================================================

To find the answer please study DATEDIR.BAT.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


53. How can I make a list of all my files and locate a certain file?
====================================================================

Let's assume that you have three three partitions, the drives C, D
and E. To make an ordered list of all your files you can apply e.g.
  @echo off
  if exist myfiles.lst del myfiles.lst
  for %%f in (c d e) do dir /w /o:en /s %%f:\*.* >> myfiles.lst
To be able to find a certain file add
  edit m:\myfiles.lst
The /W parameter displays the results of DIR in a wide format. The
/O:EN sort the results by extension and name. The /S parameter
traverses also all the subdirectories.

Another option which lists all your files, this time with with paths
included, but without the ordering, is
  @echo off
  if exist myfiles.tmp del myfiles.tmp
  for %%f in (c d e) do chkdsk /v %%f: >> myfiles.tmp
  type myfiles.tmp | find "\" | find /v "Directory " > myfiles.lst
  del myfiles.tmp
To be able to find a specific file on your harddisk add
  type myfiles.lst | find /i "%1"
The FIND parameter /V displays the lines where the target does not
exist. The /I parameter specifies a non-case sensitive search.

The same approach can be extended to find e.g. all the hidden files
on your harddisk. This is how it goes
  @echo off
  if exist myfiles.tmp del myfiles.tmp
  for %%f in (c d e) do attrib /s %%f:\*.* >> myfiles.tmp
  find "H      " < myfiles.tmp
  find "HR     " < myfiles.tmp
  del myfiles.tmp
The /S switch in ATTRIB means scanning also all the subdirectories.

I regularly make three complementary kinds of logs of all the files
I have on my harddisk. Below is a useful batch for the task. A
C:\DIRLOG directory is assumed to exist.
  @echo off
  rem Help if necessary
  if "%1"=="" goto _help
  ::
  rem Check that the PC has an identification
  if "%pcid_%"=="" goto _nopcid
  ::
  rem Which drive will we list
  set drive_=%1
  if not exist %drive_%:\nul goto _nodrive
  ::
  rem Make a list of the files on the drive
  c:
  cd \dirlog
  echo on
  dir /w /o:en /s %drive_%:\*.* > c:\dirlog\%pcid_%%drive_%.hak
  tree %drive_%:\ > c:\dirlog\%pcid_%%drive_%.tre
  chkdsk /v %drive_%: > c:\dirlog\%pcid_%%drive_%.pth
  @echo off
  set drive_=
  goto _out
  ::
  :_nopcid
  echo Environment variable PCID_ identifying your PC is not set, exiting
  echo Set it in your autoexec.bat
  goto _out
  ::
  :_nodrive
  echo Drive %drive_%: not found
  set drive_=
  goto _out
  ::
  :_help
  echo Usage: %0 [DriveLetter]
  ::
  :_out
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


54. How can I tell if a batch is running in a Windows dosbox?
=============================================================

One can utilize the fact that under Windows the "windir" environment
variable is set. However, since it is in lower case, the status must
be tested in a roundabout way. I have tested this code on Windows
3.11 only.
  @echo off
  set | find "windir=" > wintmp$$.$$$
  copy wintmp$$.$$$ winbox$$.$$$ > nul
  if exist winbox$$.$$$ echo Running under Windows
  if not exist winbox$$.$$$ echo Not running under Windows
  if exist wintmp$$.$$$ del wintmp$$.$$$
  if exist winbox$$.$$$ del winbox$$.$$$
To find out the directory from which Windows was launched see Tom
Lavedas's http://www.zdnet.com/pcmag/pclabs/solution/uu1506c.htm.

-From: Gerry Kroll
-Newsgroups: alt.msdos.batch
-Subject: Re: Is DOS Running
-Date: 31 Jan 1998 02:48:44 GMT
-Organization: Public Works & Government Services (Gov't of Canada)

The above requires a small explanation:
   FIND from DOS versions before 6.0 did not set an ERRORLEVEL to
indicate the success or failure of the search.
   FIND, when used as shown above, produces *no* output when the
file being inspected does not contain any lines with the search
object. If the output of FIND is sent to a file and the search
object doesn't exist (the search fails), the result is a zero-length
file.
   You can't test for a zero-length file directly; what CAN be done
is to use COPY.  COPY will not copy a zero-length file (I hope they
NEVER fix that!!). Thus, if the copy of the original file exists,
the original file must have had a length other than zero. Therefore,
if the copy exists, the output of FIND consisted of at least one
line, and therefore the search object exists in the original file
being inspected through FIND.
   The whole thing is a LOT simpler if you have DOS 6.0 or higher.
Just run the FIND and test for the correct ERRORLEVEL.  Type  HELP
FIND at the DOS prompt.
   Regards,
   Gerry Kroll, PWGSC, Government of Canada

Timo's addition: Under MS-DOS 6+ the batch could be written as given
below. Note the required order of testing the errorlevels.
  @echo off
  set | find "windir=" > nul
  if errorlevel==1 goto _1
  if errorlevel==0 goto _0
  :_0
  echo Running under Windows
  goto _out
  :_1
  echo Not running under Windows
  :_out

 A2: Another method is to make a WIN.BAT file at path before the
Windows directory and set an environment variable to indicate that
Windows has been loaded. It is also a good usage to reset the prompt
to show you when you are in a dosbox.
  @echo off
  set prompt_=%prompt%
  set prompt=%prompt_%[win]
  set win_=winbox
  c:\windows\win
  set prompt=%prompt_%
  set prompt_=
  set win_=
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


55. How can a test that there is a disk in a floppy disk drive?
===============================================================

The code is given below. It owes much to a posting on the Usenet
news by the batch programming wizard Tom Lavedas with personal
touches and commentary from yours truly.
  @echo off
  if "%1"=="" goto _help
  ctty nul
  %comspec% /f /c dir %1: | find "Directory of "
  ctty con
  if errorlevel==0 if not errorlevel==1 goto _isready
  echo Drive %1 is NOT ready
  goto _end
  ::
  :_isready
  echo Drive %1 is ready
  goto _end
  ::
  :_help
  echo Usage %0 [DriveLetter]
  ::
  :_end

Let's take a closer look at this instructive batch.
 1) "@echo off" turns off echoing on the subsequent lines. The @
    prevents echoing of the command itself.
 2) If no parameter was given "if "%1"=="" goto _help" presents the
    required syntax.
 3) "ctty nul" alters the default input device from the default
     con(sole) to nothing preventing any user input.
 4) "%comspec% /f /c dir %1:" call the directory command via the
    command interpreter. The undocumented /f switch avoids the
    "Abort, Retry, Fail?" input requirement if the disk is not
    present. The /c switch specifies that the command interpreter is
    to exit immediately after performing the task. Else there
    multiple shelling would pile up that would need a corresponding
    exit. The "%comspec%" environment variable specifies where the
    COMMAND.COM file is located. The "%comspec%" environment
    variable is set by a shell= line in the CONFIG.SYS file.
 5) | find "Directory of " pipes the result of "dir" to the find
    command. If a disk is present in the drive the string will be
    found and "find" returns an errorlevel of 0. Else it will return
    a higher errorlevel value.
 6) "ctty con" turns input back to the console i.e. the keyboard.
 7) "if errorlevel==0 if not errorlevel==1 goto _isready" test
    whether the value of the errorlevel is zero. If it is then the
    batch jumps to the label ":_isready". Note that logically the
    part "if errorlevel==0" is superfluous. It is there how a
    specific errorlevel value (zero) can be tested for. For more on
    testing the errorlevel see LEVEL.BAT.
 8) Most of the rest of the batch is obvious and does not need extra
    comments. In "echo Usage %0 [DriveLetter]" the %0 returns with
    path the name of the batch being run.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


56. Could you please solve this problem for me with a batch?
============================================================

There is a fine line between asking for advice and trying to exploit
others with free consultation requests. It is not uncommon to see
Usenet news postings, or even email, where a user asks to have
his/her particular problem programmed for him/her. I do not consider
this fair nor quite proper. The purpose of FAQs like the current one
is to provide the readers with batch usage information and useful
tools, not to do their work on their behalf for free.
   Requests for homework assignment solutions are another phenomenon
which regularly occur on some programming newsgroups on the Usenet
news. It is not conductive to learning to help students to cheat on
their homework assignments. Here is what you, a student, should do.
First study. Start the assignment yourself. Try your very best to
solve your assignment. Then, if you really get stuck after having
tried very very hard yourself, come back on the appropriate Usenet
newsgroup with specific questions and the code which you have
devised so far. That kind of help will usually be forthcoming. But
please do not email such questions. We are not your individual
tutors.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


57. How can I make a loop that is repeated a preset number of times?
====================================================================

The solution below, edited only in the slightest to make the style
compatible, was posted to Usenet newsgroup news:alt.msdos.batch by
Ted Davis. Ted is a major contributor in the newsgroup with very
neat batch solutions.
  @echo off
  set count_=
  set target_=!!!!!
  :_loop
    echo This is one pass %count_%
    set count_=%count_%!
    if "%count_%"=="%target_%" goto _endloop
    goto _loop
  :_endloop
  set count_=
  set target_=
The URL http://gearbox.maem.umr.edu/~batch/intrin1.htm#bang has more
on this issue.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


58. How can I display the contents of the memory?
=================================================

Here is the outline
  @echo off
  echo d 0000:0000  > infile.dbg
  echo d 0000:0080 >> infile.dbg
  echo d 0000:0100 >> infile.dbg
  echo d 0000:0180 >> infile.dbg
  echo d 0000:0200 >> infile.dbg
  echo q           >> infile.dbg
  debug < infile.dbg | more
  del infile.dbg

A detail. In the PC memory addressing conventions the line
  echo d 0000:0180 >> infile.dbg
is equivalent to line
  echo d 0010:0080 >> infile.dbg
The memory addresses are in hexadecimal. E.g. the above (180H) is
384 in decimal.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


59. How get today's date into a six-character environment variable?
===================================================================

This fairly difficult task has become quite a frequently asked
question. The demonstration batch below does the trick. It assumes
that the date is of the format "Current date is Mon 13/04/1998",
i.e. that the date separator is a slash (but this is easy to
customize). Perhaps the most common application of getting the date
into the 980413 format is making date-dependent file names, such as
e.g. TS980413.TXT . The main trick that the batch below uses is
making several passes by calling itself in the for statements. That
could be avoided, but the batch would become very long if the for
statements were written out to avoid the need of recursion.

  @echo off

  rem Determine which pass we are making
  if "%1"=="" goto _1stpass
  if "%2"=="" goto _wdpass
  if "%3"=="" goto _daypass
  if "%4"=="" goto _mmpass

  rem Extract the year
  find "/19%4" tmp$$$.$$$ > nul
  if not errorlevel==1 if errorlevel==0 set yearnr_=%4
  find "/20%4" tmp$$$.$$$ > nul
  if not errorlevel==1 if errorlevel==0 set yearnr_=%4
  goto _end

  rem Extract the month
  :_mmpass
  find "/%3/" tmp$$$.$$$ > nul
  if not errorlevel==1 if errorlevel==0 set monthnr_=%3
  goto _end

  rem Extract the day
  :_daypass
  find " %2/" tmp$$$.$$$ > nul
  if not errorlevel==1 if errorlevel==0 set daynr_=%2
  goto _end

  rem As an extra demo also get the name of the weekday
  :_wdpass
  find "%1" tmp$$$.$$$ > nul
  if not errorlevel==1 if errorlevel==0 set weekday_=%1
  goto _end

  rem Put the date in a file so that find can be applied on it
  :_1stpass
  echo.|date > tmp$$$.$$$

  rem Go through all the alternatives. Note the dummy x parameters
  rem to determine which part of the date is being processed
  for %%d in (Sun Mon Tue Wed Thu Fri Sat) do call %0 %%d
  for %%d in (01 02 03 04 05 06 07 08 09 10) do call %0 x %%d
  for %%d in (11 12 13 14 15 16 17 18 19 20) do call %0 x %%d
  for %%d in (21 22 23 24 25 26 27 28 29 30 31) do call %0 x %%d
  for %%d in (01 02 03 04 05 06 07 08 09 10 11 12) do call %0 x x %%d
  for %%d in (97 98 99 00 01 02) do call %0 x x x %%d

  rem Show the results
  echo %weekday_%
  echo %yearnr_%%monthnr_%%daynr_%

  rem Clean up
  set weekday_=
  set daynr_=
  set monthnr_=
  set yearnr_=
  del tmp$$$.$$$
  :_end
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


60. How can I find and copy the files updated today in a directory?
===================================================================

To solution with batch commands only is given below. Specialized
programs, however, are more convenient and flexible. For example
ftp://garbo.uwasa.fi/pc/filecopy/pcopy93.zip.
  @echo off
  ::
  rem Put the current date into an environment variable "datenow_"
  echo.| date | find "Current" > tmp$$$.bat
  echo set datenow_=%%4> current.bat
  call tmp$$$
  ::
  rem Clean up a bit
  del current.bat
  del tmp$$$.bat
  ::
  rem Copy all the files in a directory updated today to a floppy
  ::
  rem Clean up some more
  xcopy *.* a:\ /-y /p /d:%datenow_%
  set datenow_=
The XCOPY switch /-Y means that your permission is asked before
overwriting any file. The switch /P ask before copying any file. The
/D: switch tell that files made at %datenow_% (or later) are to be
copied.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


61. How can I test in a batch whether a TSR program has been loaded?
===================================================================

Here is an example that does that. The example tests if the SMARTDRV
is resident in memory, but it could be any TSR.
  @echo off
  mem /c | find "SMARTDRV" > nul
  if errorlevel==2 goto _nofind
  if errorlevel==1 goto _nofind
  echo SMARTDRV is loaded
  goto _end
  :_nofind
  echo SMARTDRV is not loaded
  :_end
Another similar, even better way of doing the same thing is
  @echo off
  mem /m smartdrv | find "is using the following memory" > nul
  if errorlevel==2 goto _nofind
  if errorlevel==1 goto _nofind
  echo SMARTDRV is loaded
  goto _end
  :_nofind
  echo SMARTDRV is not loaded
  :_end
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


62. Putting the current drive letter into an environment variable.
==================================================================

The trick is the same as in the item #18 including the trick how to
put the current directory into an environment variable.
  @echo off
  echo @echo off> volume.bat
  echo set getdrv_=%%3>> volume.bat
  dir | find "Volume"> go.bat
  call go
  if exist volume.bat del volume.bat
  if exist go.bat del go.bat
  ::
  rem show that we got it
  echo %getdrv_%
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


63. How can I extract the drive letter from a full file path?
=============================================================

Here goes, assuming a full path has been given! Does not work on
write protected drives.
  @echo off
  if "%1"=="" goto _usage
  ::
  rem Get the current drive letter
  echo @echo off> volume.bat
  echo set origdrv_=%%3>> volume.bat
  dir | find "Volume"> go.bat
  call go
  if exist volume.bat del volume.bat
  if exist go.bat del go.bat
  ::
  rem Change to the drive where the program is (trick due to Tom Lavedas)
  rem The \ makes to change the drive instead of running the program
  %1\
  ::
  rem Get the drive letter after the change
  @echo off
  echo @echo off> volume.bat
  echo set getdrv_=%%3>> volume.bat
  dir | find "Volume"> go.bat
  call go
  if exist volume.bat del volume.bat
  if exist go.bat del go.bat
  ::
  rem Go back to the original drive
  %origdrv_%:
  set origdrv_=
  ::
  rem Show the result
  echo %getdrv_%
  goto _end
  ::
  :_usage
  echo Usage: %0 [FullPath, e.g. C:\DOS\ANSI.SYS]
  :_end
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


64. How can I write a "SLEEP" command to pause for a certain time?
==================================================================

If the delay you want is no more than 99 seconds the answer is
fairly simple. All you need is the CHOICE command with appropriate
options. For example the following batch pauses for ten seconds. You
can, if you wish, break the wait by pressing the key b.
  @echo off
  choice /cb /t:b,10 /n > nul
  rem      ^    ^ "use b as the a break the wait key"
For longer waits a loop is needed. The following batch sets a ten
minute wait. Remove the line "echo %count_%" if you do not wish any
progress report output.
  @echo off
  set count_=.
  set target_=...........
  :_loop
  echo %count_%
  choice /cb /t:b,60 /n > nul
  set count_=.%count_%
  if not "%count_%"=="%target_%" goto _loop
  :_end
As so many items, parts of this one owe to the insights of Tom
Lavedas, and parts are totally my own (un)doing.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


65. How can put comments into a batch file?
===========================================

There are three major options, rem, ::, and %%. Rem is the best
known, %% the least. The advantage with %% is that in can be used as
a trailing comment on a working batch line. The example below
illustrates. Furthermore, a rem can be used to create an empty file.
  @echo off             %Comment: Turn off the echo%
  rem > empty.tmp       %Comment: Create on empty file%
  dir empty.tmp
  ::
  :: Comment: Test if the drive can be written to
  if exist empty.tmp echo drive is writable
  rem
  rem Comment: Delete the empty test file
  if exist empty.tmp del empty.tmp
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


66. How can I echo just the word "off" in a batch file?
=======================================================

One can't use "echo off" since that is a command for turning off the
echo. The seldom, if ever, needed curiosity, taken from "MicroSoft's
Undocumented Features, Volume 1  Number 7" is this
  @echo off
  echo.off
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


67. How can I extract the first two characters of a file name?
==============================================================

The batch below shows how to do the task. It assumes that you have
QBASIC available. QBASIC.EXE comes with MS-DOS, at least with
version 6.22. If you have Windows95 first get it and the related
.HLP files from the system's CD-ROM. I do not use Windows95 myself,
but I believe that these files are located at \OTHER\OLDMSDOS.
   The ideas utilized below can easily be applied to other string
manipulation tasks as well.
  @echo off
  ::
  :: If no parameter is given to the batch, show its proper usage
  if "%1"=="" goto _help
  ::
  :: Prepare a QBASIC program to extract the first two characters
  :: Handle different file name types like NAME.DAT NAME and .DAT
  echo LET a$="%1" > tmp$$$.bas
  echo LET p = INSTR(1, a$, ".") - 1 >> tmp$$$.bas
  echo IF p = 0 THEN LET a$ = "" >> tmp$$$.bas
  echo IF NOT (p=-1) AND NOT (p=0) THEN LET a$ = MID$(a$, 1, p) >> tmp$$$.bas
  echo LET a$ = MID$(a$, 1, 2) >> tmp$$$.bas
  echo OPEN "tmp###.bat" FOR OUTPUT AS #1 >> tmp$$$.bas
  echo PRINT #1, "@echo off" >> tmp$$$.bas
  echo PRINT #1, "set first2_=" + a$ >> tmp$$$.bas
  echo SYSTEM >> tmp$$$.bas
  qbasic /run tmp$$$.bas
  ::
  :: Call the batch created by the QBASIC program
  call tmp###.bat
  ::
  :: Demonstrate that the result is in the first2_ environment variable
  echo The first two characters of the file name %1 are %first2_%
  goto _end
  ::
  :_help
  echo Usage %0 [NameToBeTruncated]
  ::
  :: Cleanup
  :_end
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  set first2_=

The above is not the only alternative. One can do this particular
task also without QBASIC with the trick also used in explaining
"getting the file name extension". Ralf Buschmann kindly posted the
following, instructive solution. Ralf's posting is somewhat edited
below. It is slightly less general than the QBASIC solution, since
it does not test where the basename ends.
   "Here is a different approach, that does not need QBASIC. It uses
an undocumented feature of the FOR command in this versions of DOS.
The command
  for %%d in (/filename.ext) do echo %%d
will result in
  echo f
  echo ilename.ext
The "/" character causes to "cut off" the first char of the string
in MS-DOS 6.22 (but not in MS-DOS 7).
  @echo off
  if "%1"=="" goto error
  if "%2"=="" goto error
  set chars=
  if exist count.$$$ del count.$$$ >nul
  set string=%1
  ::
  :loop
  for %%d in (/%string%) do set word=%%d
  for %%d in (/%string%) do if %%d%word%==%string% set chars=%chars%%%d
  set string=%word%
  echo x>>count.$$$
  find /c "x" count.$$$|find "%2" >nul
  if errorlevel 1 goto loop
  ::
  set word=
  set string=
  del count.$$$
  echo The first %2 characters of "%1" are "%chars%".
  goto out
  ::
  :error
  echo Usage: GETCHARS [String] [NumberOfChars]
  ::
  :out
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


68. How can I compare two numbers with batch commands?
======================================================

   There are a number of batch tasks which are readily possible by
using QBASIC. QBASIC.EXE comes with MS-DOS, at least with version
6.22. If you have Windows95 first get it and the related .HLP files
from the system's CD-ROM. I do not use Windows95 myself, but I
believe that these files are located at \OTHER\OLDMSDOS. Using
QBASIC as an aid in batch files opens a Pandora's box of
possibilities.
   One hitch in using QBASIC in batch files is that ">" and "<" are
not available, since their nature as batch redirection symbols is
overrides their role as comparison operators. The batch for the
comparison of two numbers given below demonstrates one case of
needing to circumvent the redirection / comparison symbol dilemma.
   The result of comparing the two numbers is coded as follows. If
the first is smaller, equal, greater than the second the environment
variable gt_ is returned as -1, 0, and 1, respectively. (As some
programmers will recognize, this resembles the early FORTRAN
convention.)
  @echo off
  if "%2"=="" goto _help
  ::
  echo IF INSTR(STR$(%1 - %2), "-") = 0 THEN > tmp$$$.bas
  echo   LET gt$ = "1" >> tmp$$$.bas
  echo ELSE >> tmp$$$.bas
  echo   LET gt$ = "-1" >> tmp$$$.bas
  echo ENDIF >> tmp$$$.bas
  echo IF %1 = %2 THEN gt$ = "0" >> tmp$$$.bas
  echo OPEN "tmp###.bat" FOR OUTPUT AS #1 >> tmp$$$.bas
  echo PRINT #1, "@echo off" >> tmp$$$.bas
  echo PRINT #1, "set gt_=" + gt$ >> tmp$$$.bas
  echo SYSTEM >> tmp$$$.bas
  qbasic /run tmp$$$.bas
  call tmp###.bat
  echo %gt_%
  goto _end
  ::
  :_help
  echo Usage %0 [FirstNumberToBeCompared] [SecondNumberToBeCompared]
  ::
  :_end
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  set gt_=

Operations which do not initially require a ">" are more
straightforward. Below, as an example, is a further example batch to
do simple arithmetic operations utilizing QBASIC.
  @echo off
  ::
  :: Check that the syntax is right
  if "%3"=="" goto _help
  set ok_=false
  if "%2"=="+" set ok_=true
  if "%2"=="-" set ok_=true
  if "%2"=="*" set ok_=true
  if "%2"=="/" set ok_=true
  if "%2"=="^" set ok_=true
  if "%2"=="\" set ok_=true
  if "%2"=="mod" set ok_=true
  if not "%ok_%"=="true" goto _error
  ::
  :: Error message to be used should the QBASIC program fail
  echo @echo Illegal operation! The QBASIC program failed.> tmp###.bat
  ::
  :: The calculations using QBASIC
  echo ON ERROR GOTO Endit > tmp$$$.bas
  echo LET x$ = LTRIM$(STR$ (%1 %2 %3)) >> tmp$$$.bas
  echo OPEN "tmp###.bat" FOR OUTPUT AS #1 >> tmp$$$.bas
  echo PRINT #1, "@echo off" >> tmp$$$.bas
  echo PRINT #1, "set x_=" + x$ >> tmp$$$.bas
  echo Endit: >> tmp$$$.bas
  echo SYSTEM >> tmp$$$.bas
  qbasic /run tmp$$$.bas
  call tmp###.bat
  ::
  :: Show the result
  if not "%x_%"=="" echo %x_%
  goto _out
  ::
  :: Errors and help
  :_error
  echo Unknown arithmetic operation %2
  :_help
  echo Usage: %0 FirstOperand ArithmeticOperation SecondOperand
  ::
  :: Cleaning
  :_out
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  set ok_=
  set x_=

Here is another, very similar solution for the comparison. It uses
the SGN function.
  @echo off
  ::
  if "%2"=="" goto _help
  ::
  >  tmp$$$.bas echo LET a = %1
  >> tmp$$$.bas echo LET b = %2
  >> tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "@echo off"
  >> tmp$$$.bas echo IF SGN(a - b) = 1 THEN
  >> tmp$$$.bas echo   PRINT #1, "set sgn=1"
  >> tmp$$$.bas echo ELSEIF SGN(a - b) = -1 THEN
  >> tmp$$$.bas echo   PRINT #1, "set sgn=-1"
  >> tmp$$$.bas echo ELSE
  >> tmp$$$.bas echo   PRINT #1, "set sgn=0"
  >> tmp$$$.bas echo END IF
  >> tmp$$$.bas echo CLOSE #1
  >> tmp$$$.bas echo SYSTEM
  ::
  qbasic /run tmp$$$.bas
  call tmp###.bat
  ::
  if "%sgn%"=="1"  echo The first parameter is bigger than the second
  if "%sgn%"=="-1" echo The first parameter is smaller than the second
  if "%sgn%"=="0"  echo The parameters are equal
  ::
  del tmp$$$.bas
  del tmp###.bat
  goto _end
  ::
  :_help
  echo Usage: %0 FirstNumber SecondNumber
  :_end
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


69. All these solutions are for wimps. Why not rather use 4DOS?
===============================================================

4DOS is a fine alternative command interpreter that can be used to
replace MS-DOS COMMAND.COM. There are many tasks that can be
performed simply and effectively with it. For example, arithmetic
calculations considered earlier in this FAQ could be easily done
with EVAL instead of using the BASIC solutions of the vanilla
MS-DOS. However, using 4DOS also poses some problems.
  1) You have to decide whether the extra features are worth the
     hassle of changing the command interpreter.
  2) You have to weigh the advantages against the inconvenience of
     the incompatibilities. Not only of batches, but some programs
     will cease working properly if you change your command
     interpreter.
There always are better, or just other solutions, which the users of
an alternative system are eager to press on others. This is why one
often can see on the Usenet operating system advocacy postings which
are almost religious in their fervor.
   Whatever the pros and cons of 4DOS vs. COMMAND.COM, this package
has been written for vanilla MS-DOS. It does not utilize any 4DOS
additional features.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


70. How can I give more than the nine parameters to a batch?
============================================================

If you need to preserve the parameters for later usage in the batch,
the method is the one below. SHIFT is a batch command that shifts
(what else) left the positions of the replaceable parameters.
  @echo off
  set _1=%1
  shift
  set _2=%1
  shift
  set _3=%1
  shift
  set _4=%1
  shift
  set _5=%1
  shift
  set _6=%1
  shift
  set _7=%1
  shift
  set _8=%1
  shift
  set _9=%1
  shift
  set _10=%1
  :: Test
  echo %_1% %_2% %_3% %_4% %_5% %_6% %_7% %_8% %_9% %_10%
Beware, however, lest the command line call exceed the maximum
length of an MS-DOS line.

If you just need the paramters once, you can use a loop
  @echo off
  if "%1%"=="" goto _end
  :_loop
    echo %1
    shift
    if not "%1"=="" goto _loop
  :_end
  echo Finished
Or, alternatively
  @echo off
  :_loop
    if "%1"=="" goto _out
    echo %1
    shift
    goto _loop
  :_out
  echo Finished
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


71. How can I update copy files from one directory to another?
==============================================================

Copying more recent files is a task which is best done with a third
party utility like

 112492 Sep 7 1993 ftp://garbo.uwasa.fi/pc/filecopy/pcopy93.zip
 pcopy93.zip Norm Patriquin's fabulous copy program

 18016 Sep 29 1992 ftp://garbo.uwasa.fi/pc/pcmagutl/dirmat31.zip
 dirmat31.zip Dirmatch update for comparing & manipulating two dirs

It is, however, possible to use a batch only solution even if it is
not as crisp.
  @echo off
  ::
  :: Decide where to go
  if "%3"=="recurse" goto _subru
  if "%2"=="" goto _usage
  if not exist %1 goto _nofiles
  ::
  :: Do it one file at a time
  for %%f in (%1) do call %0 %%f %2 recurse
  goto _end
  ::
  :_subru
  dir %1 | find /v " Volume " | find /v " Directory " | find /v " bytes"
  echo %1
  replace /u /p %1 %2
  goto :_end
  ::
  :_nofiles
  echo File %1 not found
  goto :_end
  ::
  :_usage
  echo Usage: %0 [drive1:][path1]filename [drive2:][path2]
  ::
  :_end
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


72. How can I best clear all the files from my TEMP directory?
==============================================================

First a warning. Be very careful with this solution, since DELTREE
is a very powerful command.
  @echo off
  ::
  :: Require running under vanilla MS-DOS
  set | find "windir=" > nul
  if errorlevel==1 goto _1
  if errorlevel==0 goto _0
  :_0
  echo Do not run this batch under Windows
  goto _out
  :_1
  ::
  :: Customize the next line. Be vary careful!
  set tempdir=c:\temp
  if "%tempdir%"=="" goto _nospace
  ::
  :: Check if there is anything to delete
  if not exist %tempdir%\*.* goto _nofiles
  deltree /y %tempdir%\
  goto _out
  ::
  :_nofiles
  echo No files in, or no %tempdir%
  goto _out
  ::
  :_nospace
  echo Warning! You are out of environment space
  ::
  :_out
  set tempdir=
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


73. How can I check the number of parameters given to a batch?
==============================================================

A pedestrian solution to this question is
  @echo off
  if not "%9"=="" echo at least 9 replaceable parameters
  if "%9"=="" if not "%8"=="" echo 8 replaceable parameters
  if "%8"=="" if not "%7"=="" echo 7 replaceable parameters
  if "%7"=="" if not "%6"=="" echo 6 replaceable parameters
  if "%6"=="" if not "%5"=="" echo 5 replaceable parameters
  if "%5"=="" if not "%4"=="" echo 4 replaceable parameters
  if "%4"=="" if not "%3"=="" echo 3 replaceable parameters
  if "%3"=="" if not "%2"=="" echo 2 replaceable parameters
  if "%2"=="" if not "%1"=="" echo 1 replaceable parameters
  if "%1"=="" echo no replaceable parameters
This is not, however, a very essential batch task since e.g. "shift"
can be used to access one parameter at a time until the parameters
are exhausted.
   Another solution is a batch that gives the output as a number of
characters (.)
  @echo off
  set count_=
  :_loop
    if "%1"=="" goto _endloop
    shift
    set count_=%count_%.
    goto _loop
  :_endloop
  if not "%count_%"=="" echo %count_%
  if "%count_%"=="" echo No parameters
This method has the disadvantage of losing the parameters because of
the shift.
   A rather neat solution was posted by Walter Zackery:
@echo off
>>{c}.bat for %%f in (1 2 3 4 5 6 7 8 9) do echo if not "%%%%f"=="" set c_=%%f
call {c} %1 %2 %3 %4 %5 %6 %7 %8 %9
if exist {c}.bat del {c}.bat
echo %c_% parameters entered at the command line.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


74. How can I locate and e.g. delete all *.TMP files on a drive?
================================================================

The locating part is not difficult with a batch, but also performing
an operation on the files found is. Therefore, I'll recommend a
third party solution for the latter part. As for the first part, you
can use the ATTRIB command as follows
  @echo off
  attrib +a c:\*.tmp /s > nul
  attrib c:\*.tmp /s > go.bat
Then you'll have a list like
  A          C:\AN\ARCHIVE.TMP
  A          C:\AN\NOTES.TMP
  A          C:\AN2\NOTES2.TMP
The next question is how to manipulate that list of files. One
non-batch solution is to use an editor to substitute the "  A" (or
whatever) with an MS-DOS command, like DEL.
   A different, stand-alone solution is to use a specified
third-party program for the purpose. The best choices are the very
useful and flexible TARGET
 73962 Jul 21 1992 ftp://garbo.uwasa.fi/pc/filefind/target15.zip
 target15.zip The McAfee File Locator and Manipulator (good)
and the more narrow-scope
 17653 Dec 13 1987 ftp://garbo.uwasa.fi/pc/pcmagvol/vol4n24.zip
 vol4n24.zip Contains SWEEP and WAITASEC
Also see the later item "How to search all the *.txt files on a
drive for a word?"
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


75. How can I rename all files sequentially in a directory?
===========================================================

 Q: How can I rename all files in a directory into a sequential
numerical order? E.g. 001.txt, 002.txt, 003.bat, 004.ico.

 A: This is an interesting task. The solution I have used for a
similar task involves an editor, which is effective but not very
neat batch programming. For a batch only solution one alternative is
to utilize QBASIC which is part of MS-DOS. The solution below can
easily be streamlined to do the renaming automatically, but I have
erred on the side of caution. Yes, don't damage your file structure
with haphazard experimenting. First make sure that you understand
what the batch does.
   Also note that while this batch is for all the files in a
directory, it is very easy to change it to cover only one time of
files. Just change argument in the second line of the batch.

  @echo off
  dir /b /l *.* > dirlst$$.tmp

  echo OPEN "dirlst$$.tmp" FOR INPUT AS #1  > tmp$$$.bas
  echo OPEN "sequence.bat" FOR OUTPUT AS #2 >> tmp$$$.bas
  echo PRINT #2, "@echo off" >> tmp$$$.bas
  echo PRINT #2, "rem SEQUENCE.BAT by Prof. Timo Salmi" >> tmp$$$.bas
  echo PRINT #2, "" >> tmp$$$.bas
  echo LET i = 0 >> tmp$$$.bas
  echo DO >> tmp$$$.bas
  echo  LINE INPUT #1, a$ >> tmp$$$.bas
  echo  IF NOT INSTR(a$, ".") = 0 THEN >> tmp$$$.bas
  echo   IF NOT a$ = "dirlst$$.tmp" THEN >> tmp$$$.bas
  echo    IF NOT a$ = "sequence.bat" THEN >> tmp$$$.bas
  echo     LET i = i + 1 >> tmp$$$.bas
  echo     LET i$ = LTRIM$(STR$(i)) >> tmp$$$.bas
  echo     LET z$ = STRING$(3 - LEN(i$), ASC("0")) >> tmp$$$.bas
  echo     LET e$ = MID$(a$, INSTR(a$, ".")) >> tmp$$$.bas
  echo     PRINT #2, "copy /-y "; a$; " "; z$; i$ + e$ >> tmp$$$.bas
  echo    END IF >> tmp$$$.bas
  echo   END IF >> tmp$$$.bas
  echo  END IF >> tmp$$$.bas
  echo LOOP UNTIL (EOF(1)) >> tmp$$$.bas
  echo CLOSE #1 >> tmp$$$.bas
  echo CLOSE #2 >> tmp$$$.bas
  echo SYSTEM >> tmp$$$.bas

  qbasic /run tmp$$$.bas
  del tmp$$$.bas
  del dirlst$$.tmp

  echo.
  echo Batch file SEQUENCE.BAT should be now ready for your task.
  echo.
  echo It is advisable to first look into it before running it.
  echo As added caution copying is used instead of renaming.
  echo.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


76. How to search all the *.txt files on a drive for a word?
============================================================

The easiest alternative would be using third-party solutions such as
 73962 Jul 21 1992 ftp://garbo.uwasa.fi/pc/filefind/target15.zip
 target15.zip The McAfee File Locator and Manipulator (good)
For a batch-only solution this is not an easy task unless one fully
utilizes the tools available in MS-DOS version 6.22. The batch below
prepares a QBASIC program for the sweep. If you understand the
solution you can customize it e.g. to accept strings instead of just
words, if need be. The version below is case-insensitive. For a case
sensitive alternative omit the /I from the FIND.
  @echo off
  dir /b /s c:\*.txt > dirlst$$.tmp
  if "%1"=="" goto _help
  ::
  echo LET q$ = CHR$(34) > tmp$$$.bas
  echo LET p$ = CHR$(37) >> tmp$$$.bas
  echo LET g$ = CHR$(62) >> tmp$$$.bas
  echo OPEN "dirlst$$.tmp" FOR INPUT AS #1  >> tmp$$$.bas
  echo OPEN "sweep$$$.bat" FOR OUTPUT AS #2 >> tmp$$$.bas
  echo PRINT #2, "@echo off" >> tmp$$$.bas
  echo PRINT #2, "rem SWEEP$$$.BAT by Prof. Timo Salmi "; DATE$ >> tmp$$$.bas
  echo PRINT #2, >> tmp$$$.bas
  echo WHILE NOT EOF(1) >> tmp$$$.bas
  echo   INPUT #1, a$ >> tmp$$$.bas
  echo   PRINT #2, "FIND /I "; q$; p$; "1"; q$, a$; g$; g$ " sweep$$$.out" >> tmp$$$.bas
  echo WEND >> tmp$$$.bas
  echo CLOSE #1 >> tmp$$$.bas
  echo CLOSE #2 >> tmp$$$.bas
  echo SYSTEM >> tmp$$$.bas
  ::
  if exist sweep$$$.out del sweep$$$.out
  qbasic /run tmp$$$.bas
  del tmp$$$.bas
  del dirlst$$.tmp
  call sweep$$$ %1
  del sweep$$$.bat   %Omit, if you wish to customize the search%
  ::
  type sweep$$$.out | more
  del sweep$$$.out
  goto _end
  ::
  :_help
  echo Usage %0 [SearchWord]
  :_end

Consider one related detail of writing batches with QBASIC. Some
characters like " (ASCII 34) % (ASCII 37) and > (ASCII 62) require
special treatment. If they are needed in a PRINT you can apply the
trick used above. That is, define a variable that contains the
character needed and use that in the print statement. The most
tricky situation is if you need to use a > or a < within the QBASIC
program to compare two number. Item #68 of this FAQ shows how to
solve this.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


77. How can I give multiple commands on one line?
=================================================

Take a look at REPEAT.BAT in my batch file FAQ / batch collection.
 Usage: REPEAT [FileName1] [FileName2] [FileName3] ...
Essentially the trick is recursion in batch programming.

Also take a look at M.BAT
 echo Usage: M [Command1] [Pars] [-] [Command2] [Pars2] [...]
Essentially the trick is utilizing shift.
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


78. Is there a batch to individually zip each file in a directory?
==================================================================

 Q: "Is there a way that I can use an MS-DOS batch to PKzip all the
files in a directory without knowing what the files' names are? For
example, if I had two files in a directory SUE.DOC and FRED.TXT. I
do not know the names prior to running the batch file, but I want to
end up with two files zipped as SUE.ZIP and FRED.ZIP."

 A: If one (again) resorts to running QBASIC through a batch file,
this task can be done readily enough:
  @echo off
  ::
  :: Prepare a list of the files in the directory
  dir /b *.* > dirlst$$.tmp
  ::
  :: Handle the directory file line by line
  echo OPEN "dirlst$$.tmp" FOR INPUT  AS #1  > tmp$$$.bas
  echo OPEN "zipper$$.bat" FOR OUTPUT AS #2 >> tmp$$$.bas
  echo WHILE NOT EOF(1) >> tmp$$$.bas
  echo   INPUT #1, a$ >> tmp$$$.bas
         :: Extract the basename
  echo   LET p = INSTR(1, a$, ".") - 1 >> tmp$$$.bas
         :: Case of only extension, no basename
  echo   IF p = 0 THEN LET a$ = "" >> tmp$$$.bas
         :: Other cases
  echo   IF NOT (p=-1) AND NOT (p=0) THEN LET a$ = MID$(a$, 1, p) >> tmp$$$.bas
         :: Make a batch to do the zipping
  echo   PRINT #2, "call pkzip ",a$,a$;".*" >> tmp$$$.bas
  echo WEND >> tmp$$$.bas
  echo CLOSE #1 >> tmp$$$.bas
  echo CLOSE #2 >> tmp$$$.bas
  echo SYSTEM >> tmp$$$.bas
  ::
  :: Run the prepared QBASIC program
  qbasic /run tmp$$$.bas
  ::
  :: Zip the files
  call zipper$$.bat
  ::
  :: Delete the auxiliary files and superfluous zip files
  if exist dirlst$$.tmp del dirlst$$.tmp
  if exist dirlst$$.zip del dirlst$$.zip
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp$$$.zip del tmp$$$.zip
  if exist zipper$$.bat del zipper$$.bat
  if exist zipper$$.zip del zipper$$.zip
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


79. A batch to substitute a string through a set of text files?
===============================================================

 Q: I need a batch to substitute "Joe" for "Fred" through all the
*.TXT text files in a directory. How do I achieve that?

 A: Sometimes it is best to give in and not insist on a pure batch
solution without third party utilities. This is one such instance.
First, consider the substitution for a single text file. Get the
Unix-like stream editor
 20368 Oct 1 1991 ftp://garbo.uwasa.fi/pc/unix/sed15x.zip
 sed15x.zip HHSED executable, E.Raymond+D.Kirschbaum+H.Helman
Here is a simple batch to do the substitution with sed on a test
file TEST1.TXT
  @echo off
  if not exist test1.txt goto _notfound
  type test1.txt | sed -e "s/Fred/Joe/g" > tmp$$$.txt
  type tmp$$$.txt
  del tmp$$$.txt
  goto _end
  :_notfound
  echo File test1.txt not found
  :_end

The above just gives the first step in the process without altering
the source file and just creating a temporary file. if you wish to
write the result back into the original file, chance the line
  type tmp$$$.txt
to
  type tmp$$$.txt > test1.txt

Next, here is how recurse all the TEST*.TXT files in the directory
and make the desired substitutions.
  @echo off
  if "%2"=="recurse" goto _recurse
  for %%f in (test*.txt) do call batfaq %%f recurse
  goto _end
  :_recurse
  type %1 | sed -e "s/Fred/Joe/g" > tmp$$$.txt
  type tmp$$$.txt > %1
  del tmp$$$.txt
  echo %1 ready
  :_end

As most Unix-like tools SED is a flexible, but not always an easy
tool to master. For example, consider the task of extracting the
base name of a file. I'll leave you to ponder the following line and
the possibilities it opens
 dir /b TEST*.TXT | sed -e "s/\.TXT//"
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


80. Where do I find a good book or WWW page on batch programming?
=================================================================

Most books on batch programming, which I have seen, are too
elementary to be really useful to the readers of this file. Hence
this list is very brief indeed.

Jamsa, Kris (1993). Concise Guide to MS-DOS Batch Files. Microsoft
  Press. (Draws heavily on DEBUG, but might be of general interest
  to you.)

Some old issues of magazines like the PC Magazine and PC Computing
contain much useful MS-DOS lore. But now they have become so
exclusively Microsoft Windows oriented (obsessed) that they have
lost all their interest and usefulness to an MS-DOS user.

For a WWW book see http://www.deltaelectronics.com/tglbatch/

For further batch material on WWW you may wish to check the links on
the links page http://www.uwasa.fi/~ts/http/http2.html#batch
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


81. How to read a file's date and time into environment variables?
==================================================================

Below is a batch solution utilizing QBASIC.
  @echo off
  ::
  :: Check the input
  if "%1"=="" goto _usage
  if not exist %1 goto _nofind
  ::
  :: Put the file's information into a file
  dir %1 > dir$$$.tmp
  ::
  :: Get the informationfrom the file
  >  tmp$$$.bas echo OPEN "dir$$$.tmp" FOR INPUT AS #1
  >> tmp$$$.bas echo FOR I = 1 to 5
  >> tmp$$$.bas echo   LINE INPUT #1, a$
  >> tmp$$$.bas echo NEXT I
  >> tmp$$$.bas echo CLOSE #1
  ::
  :: Create a batch that will set the enrironment variables
  :: May require customizing depending on your configuration
  >> tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "@echo off"
  >> tmp$$$.bas echo PRINT #1, "set filedate=" ; LTRIM$(MID$(a$,28,8))
  >> tmp$$$.bas echo PRINT #1, "set filetime=" ; LTRIM$(MID$(a$,39,5))
  >> tmp$$$.bas echo CLOSE #1
  >> tmp$$$.bas echo SYSTEM
  ::
  :: Run the QBASIC program
  qbasic /run tmp$$$.bas
  ::
  :: Run the batch that sets the environment variables
  call tmp###.bat
  ::
  :: Clean up
  del dir$$$.tmp
  del tmp$$$.bas
  del tmp###.bat
  ::
  :: Test
  echo %filedate%
  echo %filetime%
  ::
  :: Clean up
  set filedate=
  set filetime=
  goto _end
  ::
  :: Error messages
  :_usage
  echo Usage %0 Filename
  goto _end
  :_nofind
  echo File %1 not found
  ::
  :: End
  :_end
If you understand how the above works, you'll realize that it is
very easy to also read the size of the file into an environment
variable. This is left as an exercise. (Hint: Look at the
fields given by the DIR command.)
--------------------------------------------------------------------

Introduction  Index  Articles  Download the text file version with samples and utilities 


Unless stated otherwise, these pages, the programs presented and their sources are copyrighted freeware.
Use them entirely at your own risk.
The author or the creator of this page cannot be held responsible for any damage, direct nor consequential, caused by the use of, or inability to use the techniques or programs presented here, nor the programs' sources or part of the sources.
Use of any of the techniques, programs or sources presented here implies agreement with these terms.

This page created with the author's permission by Carl Parmenter