From ts@uwasa.fi Wed Jan 10 01:00:00 2001
Subject: Batchtricks file information
Date: Wed, 10 Jan 2001 01:00:00
From: ts@uwasa.fi (Timo Salmi)

Assorted Batch Tricks                            Wed 10-January-2001
=====================
                                                 All rights reserved
                               Copyright (c) 1993-2001 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 <http://www.uwasa.fi/~ts/>  ; 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 to TSBAT*.ZIP. Please do not distribute 
   this 1BATFAQ.TXT file separately! If you see this file    
   distributed alone, please alert the SysAdmin immediately. 
  

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/98/Me 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 (or later) 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.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:01 2001
Subject: Batch tricks index
Date: Wed, 10 Jan 2001 01:00:01
From: ts@uwasa.fi (Timo Salmi)

INDEX
=====

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 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) Is 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 I test if 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?
82) How would I get a beep in a batch file?
83) Y2K: My old BIOS gives a wrong year at boot. How can I fix it?
84) Is there a batch to drop the first letter of a file name?
85) How do I close the command window once my batch file has run?
86) Is MS-DOS batch programming going to die along with W2K?
87) How can I test for the existence of a substring in a string?
88) How can I put MS-DOS FIND results into an environment variable?
89) How to get months as letters and years in four digits in DIR?
90) Isn't MS-DOS dead with W2K? So why bother with MS-DOS batches?
91) How can I exit the called batch without returning to the first?
92) How do I create a sequence of directories from 1 to MaxValue?
93) How do I add +1 to a variable in a batch?
94) How to copy the errorlevel into a variable in a batch?
95) How can I test for a zero byte file?
96) How to show the last N lines of a file using DOS batch files?
97) How do I get the path of a file located somewhere on my disk?
98) How to read a file's attributes into environment variables?
99) Is it possible to echo without linefeed like the Unix echo -n?
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:02 2001
Subject: Generalizing @echo off
Date: Wed, 10 Jan 2001 01:00:02
From: ts@uwasa.fi (Timo Salmi)

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 user 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?"
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:03 2001
Subject: Deleting all files
Date: Wed, 10 Jan 2001 01:00:03
From: ts@uwasa.fi (Timo Salmi)

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".
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:04 2001
Subject: Nested for loops
Date: Wed, 10 Jan 2001 01:00:04
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:05 2001
Subject: Checking directory existence
Date: Wed, 10 Jan 2001 01:00:05
From: ts@uwasa.fi (Timo Salmi)

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. A solution that works also for
CR-ROMs is
  @echo off
  if "%1"=="" goto _usage
  set target_=%1
  ctty nul
  dir /ad  %target_% | find " file(s) "
  ctty con
  if errorlevel==2 goto _1
  if errorlevel==1 goto _1
  echo Directory %target_% exists
  goto _out
  :_1
  echo Directory %target_% does not exist
  goto _out
  :_usage
  echo Usage %0 DirectoryName
  :_out
  set target_=
The "ctty nul/ctty con" command pair suppresses displaying the "File
not found" error message if the directory does not exist. Be careful
to get the "ctty nul/ctty con" pair right lest you lock your system.

Furthermore in the "if not exist %1\nul" method 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
another alternative that does 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. On the other hand exactly that is the usefulness of this
method if the intention is to write something.
  @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
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:06 2001
Subject: Checking program existence
Date: Wed, 10 Jan 2001 01:00:06
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:07 2001
Subject: Subroutines and recursion
Date: Wed, 10 Jan 2001 01:00:07
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:08 2001
Subject: Conversion to uppercase
Date: Wed, 10 Jan 2001 01:00:08
From: ts@uwasa.fi (Timo Salmi)

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=
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:09 2001
Subject: Append new directory to path
Date: Wed, 10 Jan 2001 01:00:09
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:10 2001
Subject: Comparing two files
Date: Wed, 10 Jan 2001 01:00:10
From: ts@uwasa.fi (Timo Salmi)

9.  How can I compare if 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
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:11 2001
Subject: Writing an empty line
Date: Wed, 10 Jan 2001 01:00:11
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:12 2001
Subject: Customizing the pause message
Date: Wed, 10 Jan 2001 01:00:12
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:13 2001
Subject: Complicated renaming with for
Date: Wed, 10 Jan 2001 01:00:13
From: ts@uwasa.fi (Timo Salmi)

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
  tspa357c.zip
The following for-statement does that conveniently.
 for %f in (40 50 55 60 7c) 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:
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:14 2001
Subject: Checking for wildcards
Date: Wed, 10 Jan 2001 01:00:14
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:15 2001
Subject: Preventing breaking the batch
Date: Wed, 10 Jan 2001 01:00:15
From: ts@uwasa.fi (Timo Salmi)

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
 107499 Jul 28 1999 ftp://garbo.uwasa.fi/pc/ts/tstsr23.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".
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:16 2001
Subject: Forcing autoexec.bat execution
Date: Wed, 10 Jan 2001 01:00:16
From: ts@uwasa.fi (Timo Salmi)

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".
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:17 2001
Subject: Getting the extension
Date: Wed, 10 Jan 2001 01:00:17
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:18 2001
Subject: The quote character %
Date: Wed, 10 Jan 2001 01:00:18
From: ts@uwasa.fi (Timo Salmi)

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".
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:19 2001
Subject: Eliminating auxiliary batches
Date: Wed, 10 Jan 2001 01:00:19
From: ts@uwasa.fi (Timo Salmi)

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!
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:20 2001
Subject: Subst utilization in paths
Date: Wed, 10 Jan 2001 01:00:20
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:21 2001
Subject: Run a batch one a week
Date: Wed, 10 Jan 2001 01:00:21
From: ts@uwasa.fi (Timo Salmi)

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?
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:22 2001
Subject: Is path included in file name?
Date: Wed, 10 Jan 2001 01:00:22
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:23 2001
Subject: Display the time
Date: Wed, 10 Jan 2001 01:00:23
From: ts@uwasa.fi (Timo Salmi)

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 batch
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
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:24 2001
Subject: Testing for the errorlevel
Date: Wed, 10 Jan 2001 01:00:24
From: ts@uwasa.fi (Timo Salmi)

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".
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:25 2001
Subject: Redirecting batch output
Date: Wed, 10 Jan 2001 01:00:25
From: ts@uwasa.fi (Timo Salmi)

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 <ESC>
  :: This line will not cause problems: Press <ESC>
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".)

 A2: Tom Lavedas posted this informative tip on the Usenet news:
"Redirection only works for programs. A batch file is not a program,
but rather a script for the command processor. The command processor
IS a program, so the solution [to redirect output from a batch] is
to run the batch under a secondary copy of the command processor,
something like this ...
  %comspec% /e:2048 /c batch.bat > xy
The version 6.xx's on-line HELP command has some discussion of
redirection and additional details about using COMMAND.COM."
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:26 2001
Subject: Out of environment space
Date: Wed, 10 Jan 2001 01:00:26
From: ts@uwasa.fi (Timo Salmi)

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_=
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:27 2001
Subject: Disabling a drive
Date: Wed, 10 Jan 2001 01:00:27
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:28 2001
Subject: Escape sequence to printer
Date: Wed, 10 Jan 2001 01:00:28
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:29 2001
Subject: Creating a random string
Date: Wed, 10 Jan 2001 01:00:29
From: ts@uwasa.fi (Timo Salmi)

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".
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:30 2001
Subject: Getting string length
Date: Wed, 10 Jan 2001 01:00:30
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:31 2001
Subject: MS-DOS version into environment variable
Date: Wed, 10 Jan 2001 01:00:31
From: ts@uwasa.fi (Timo Salmi)

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.$$$
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:32 2001
Subject: Number of files on a drive
Date: Wed, 10 Jan 2001 01:00:32
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:33 2001
Subject: Numbering a file's lines
Date: Wed, 10 Jan 2001 01:00:33
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:34 2001
Subject: Push and pop a directory
Date: Wed, 10 Jan 2001 01:00:34
From: ts@uwasa.fi (Timo Salmi)

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."
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:35 2001
Subject: Date into environment variable
Date: Wed, 10 Jan 2001 01:00:35
From: ts@uwasa.fi (Timo Salmi)

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?".
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:36 2001
Subject: Identifying the individual PC
Date: Wed, 10 Jan 2001 01:00:36
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:37 2001
Subject: For loop and redirection
Date: Wed, 10 Jan 2001 01:00:37
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:38 2001
Subject: Traversing a directory tree
Date: Wed, 10 Jan 2001 01:00:38
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:39 2001
Subject: Echoing the > and >> symbols
Date: Wed, 10 Jan 2001 01:00:39
From: ts@uwasa.fi (Timo Salmi)

38. Is 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."

This is Timo again. Let's look at preparing a simple HTML file with
a batch. In HTML there are a lot of "<" and ">" symbols involved.
Batches will mistake them for redirection symbols unless the tricks
of this item are utilized. For example

  @echo off

  echo @prompt $lHTML$g > tmp$$$.bat
  %comspec% /e:2048 /c tmp$$$.bat > test.htm

  echo @prompt $lHEAD$g$lTITLE$gTest$l/TITLE$g$l/HEAD$g > tmp$$$.bat
  %comspec% /e:2048 /c tmp$$$.bat >> test.htm

  echo @prompt Whatever$lP$g$lHR$g > tmp$$$.bat
  %comspec% /e:2048 /c tmp$$$.bat >> test.htm

  echo @prompt $l/BODY$g > tmp$$$.bat
  %comspec% /e:2048 /c tmp$$$.bat >> test.htm

  echo @prompt $l/HTML$g > tmp$$$.bat
  %comspec% /e:2048 /c tmp$$$.bat >> test.htm

  del tmp$$$.bat
  dir m:\test.htm
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:40 2001
Subject: Getting the file basename
Date: Wed, 10 Jan 2001 01:00:40
From: ts@uwasa.fi (Timo Salmi)

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_=
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:41 2001
Subject: Reading user's input
Date: Wed, 10 Jan 2001 01:00:41
From: ts@uwasa.fi (Timo Salmi)

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.pressroom.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%
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:42 2001
Subject: Getting the last input parameter
Date: Wed, 10 Jan 2001 01:00:42
From: ts@uwasa.fi (Timo Salmi)

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"
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:43 2001
Subject: Creating an empty file
Date: Wed, 10 Jan 2001 01:00:43
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:44 2001
Subject: Handling disk's serial number
Date: Wed, 10 Jan 2001 01:00:44
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:45 2001
Subject: Inserting a delay
Date: Wed, 10 Jan 2001 01:00:45
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:46 2001
Subject: Batch compilers
Date: Wed, 10 Jan 2001 01:00:46
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:47 2001
Subject: Is a disk empty?
Date: Wed, 10 Jan 2001 01:00:47
From: ts@uwasa.fi (Timo Salmi)

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.

Much the same method can be used to check if a directory contains
files or not:
  @echo off
  ::
  rem Help, if necessary
  if "%1"=="" goto _help
  ::
  rem Check if directory contains any empty files
  dir %1 | find " 0 " | find /v " bytes" > found.$$$
  copy found.$$$ notempty.$$$ > nul
  if exist notempty.$$$ echo Directory %1 contains files
  if exist notempty.$$$ goto _clean
  ::
  rem Check whether the directory contains files or not
  dir %1 | find " 0 bytes" > found.$$$
  copy found.$$$ empty.$$$ > nul
  if exist empty.$$$ echo Directory %1 contains no files
  if exist empty.$$$ goto _clean
  echo Directory %1 contains files
  ::
  :_clean
  rem Clean up
  del found.$$$
  if exist empty.$$$ del empty.$$$
  if exist notempty.$$$ del notempty.$$$
  goto _end
  ::
  :_help
  echo Usage: %0 DirectoryPath
  :_end
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:48 2001
Subject: A different batch each day
Date: Wed, 10 Jan 2001 01:00:48
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:49 2001
Subject: Line numbers
Date: Wed, 10 Jan 2001 01:00:49
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:50 2001
Subject: Backup new files
Date: Wed, 10 Jan 2001 01:00:50
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:51 2001
Subject: Traversing all files
Date: Wed, 10 Jan 2001 01:00:51
From: ts@uwasa.fi (Timo Salmi)

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

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

From ts@uwasa.fi Wed Jan 10 01:00:52 2001
Subject: Debugging a batch
Date: Wed, 10 Jan 2001 01:00:52
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:53 2001
Subject: Display all files updated today
Date: Wed, 10 Jan 2001 01:00:53
From: ts@uwasa.fi (Timo Salmi)

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

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

From ts@uwasa.fi Wed Jan 10 01:00:54 2001
Subject: Listing all files
Date: Wed, 10 Jan 2001 01:00:54
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:55 2001
Subject: Windows dosbox or not
Date: Wed, 10 Jan 2001 01:00:55
From: ts@uwasa.fi (Timo Salmi)

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_=
To avoid multiple loading, you could use
  @echo off
  if not "%win_%"=="" goto _loaded
  set prompt_=%prompt%
  set prompt=%prompt_%[win]
  set win_=winbox
  c:\windows\win
  set prompt=%prompt_%
  set prompt_=
  set win_=
  goto _out
  :_loaded
  echo You have already loaded Windows and shelled to MS-DOS
  :_out
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:56 2001
Subject: Disk drive ready?
Date: Wed, 10 Jan 2001 01:00:56
From: ts@uwasa.fi (Timo Salmi)

55. How can I test if 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.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:00:57 2001
Subject: Exploiting others
Date: Wed, 10 Jan 2001 01:00:57
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:58 2001
Subject: Repeat loops
Date: Wed, 10 Jan 2001 01:00:58
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:00:59 2001
Subject: Memory contents
Date: Wed, 10 Jan 2001 01:00:59
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:00 2001
Subject: Today into a variable
Date: Wed, 10 Jan 2001 01:01:00
From: ts@uwasa.fi (Timo Salmi)

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

As usual, there are several solutions to the same problem. One of
the alternatives is to use a QBASIC approach to set the desired
environment variables. The drawback with this solution is that the
weekday is not readily available should one wish also obtain that.
  @echo off
  ::
  :: Use a QBASIC program to create a batch to set the variables
  >  tmp$$$.bas echo LET a$ = DATE$
  >> tmp$$$.bas echo LET b$ = TIME$
  >> tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "set mm_=" ; LTRIM$(MID$(a$,1,2))
  >> tmp$$$.bas echo PRINT #1, "set dd_=" ; LTRIM$(MID$(a$,4,2))
  >> tmp$$$.bas echo PRINT #1, "set yy_=" ; LTRIM$(MID$(a$,7,4))
  >> tmp$$$.bas echo PRINT #1, "set hr_=" ; LTRIM$(MID$(b$,1,2))
  >> tmp$$$.bas echo PRINT #1, "set mn_=" ; LTRIM$(MID$(b$,4,2))
  >> tmp$$$.bas echo PRINT #1, "set ss_=" ; LTRIM$(MID$(b$,7,2))
  >> 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
  ::
  :: Test that it worked
  echo Month = %mm_%
  echo Day = %dd_%
  echo Year = %yy_%
  echo Hour = %hr_%
  echo Minutes = %mn_%
  echo Seconds = %ss_%
  ::
  :: Clean up
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  set mm_=
  set dd_=
  set yy_=
  set hr_=
  set mn_=
  set ss_=

There are even other solutions that have been presented on the net
including an approach utilizing MS-DOS DEBUG and an approach
utilizing a separate MS-DOS AWK port from Unix.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:01 2001
Subject: Copying today's updates
Date: Wed, 10 Jan 2001 01:01:01
From: ts@uwasa.fi (Timo Salmi)

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

   The solution with batch commands only is given below. Specialized
programs, however, are more convenient and flexible. For example
ftp://garbo.uwasa.fi/pc/filecopy/pcopy93d.zip. A Y2K note.
Patriquin's pcopy93d.zip its date selection copy option
unfortunately ceased working correctly at the turn of the
millennium. Another option of a third party program would be
 81848 Nov 1 1995 ftp://garbo.uwasa.fi/pc/goldies/ccopy107.zip
 ccopy107.zip Controlled Copy file copier/mover, T.Toikkanen

On to the batch-only solution:
  @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.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:02 2001
Subject: Checking the status of a TSR
Date: Wed, 10 Jan 2001 01:01:02
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:03 2001
Subject: Getting the current drive
Date: Wed, 10 Jan 2001 01:01:03
From: ts@uwasa.fi (Timo Salmi)

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_%
If you want to get the volume label instead of the current drive
just use %%5 instead of %%3 in the above. The batch would be
  @echo off
  echo @echo off> volume.bat
  echo set getvol_=%%5>> volume.bat
  vol | 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 %getvol_%
The essence of this trick is that the "vol" outputs e.g.
            Volume in drive C is WAVE_C
and WAVE_C is the fifth parameter for Volume
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:04 2001
Subject: Pulling the drive from path
Date: Wed, 10 Jan 2001 01:01:04
From: ts@uwasa.fi (Timo Salmi)

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

An alternative solution utilizing QBASIC. Note how this solution
could easily also be used for extracting any part of a string
variable by simply adjusting the parameters of LTRIM$(MID$(a$,1,1)).
  @echo off
  ::
  if "%1"=="" goto _usage
  ::
  :: A QBASIC program to create a batch for the drive variable
  >  tmp$$$.bas echo LET a$ = "%1"
  >> tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "set getdrv_=" ; LTRIM$(MID$(a$,1,1))
  >> 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
  ::
  rem Show the result
  echo %getdrv_%
  ::
  :: Clean up
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  set getdrv_=
  goto _end
  ::
  :_usage
  echo Usage: %0 [FullPath, e.g. C:\DOS\ANSI.SYS]
  :_end
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:05 2001
Subject: Pausing for a moment
Date: Wed, 10 Jan 2001 01:01:05
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:06 2001
Subject: Comments in batches
Date: Wed, 10 Jan 2001 01:01:06
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:07 2001
Subject: Echoing the word off
Date: Wed, 10 Jan 2001 01:01:07
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:08 2001
Subject: Manipulating file names
Date: Wed, 10 Jan 2001 01:01:08
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:09 2001
Subject: Comparing two values
Date: Wed, 10 Jan 2001 01:01:09
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:10 2001
Subject: Real wo/men use 4DOS
Date: Wed, 10 Jan 2001 01:01:10
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:11 2001
Subject: More than 9 parameters
Date: Wed, 10 Jan 2001 01:01:11
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:12 2001
Subject: Update copy files
Date: Wed, 10 Jan 2001 01:01:12
From: ts@uwasa.fi (Timo Salmi)

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

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

 122494 Aug 5 1994 ftp://garbo.uwasa.fi/pc/filecopy/pcopy93d.zip
 Norm Patriquin's previously fabulous copy program, Y2K buggy!

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

From ts@uwasa.fi Wed Jan 10 01:01:13 2001
Subject: Clearing temp
Date: Wed, 10 Jan 2001 01:01:13
From: ts@uwasa.fi (Timo Salmi)

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=
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:14 2001
Subject: Number of parameters
Date: Wed, 10 Jan 2001 01:01:14
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:15 2001
Subject: Deleting all *.tmp files
Date: Wed, 10 Jan 2001 01:01:15
From: ts@uwasa.fi (Timo Salmi)

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?"
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:16 2001
Subject: Renaming files sequentially
Date: Wed, 10 Jan 2001 01:01:16
From: ts@uwasa.fi (Timo Salmi)

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 type of
files. Just change argument in the second line of the batch. (For
example you might have dir /b /l *.txt > dirlst$$.tmp)


  @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.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:17 2001
Subject: A sweeping find
Date: Wed, 10 Jan 2001 01:01:17
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:18 2001
Subject: Multi-command lines
Date: Wed, 10 Jan 2001 01:01:18
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:19 2001
Subject: Zipper
Date: Wed, 10 Jan 2001 01:01:19
From: ts@uwasa.fi (Timo Salmi)

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

From ts@uwasa.fi Wed Jan 10 01:01:20 2001
Subject: Blanket string substitution
Date: Wed, 10 Jan 2001 01:01:20
From: ts@uwasa.fi (Timo Salmi)

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//"
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:21 2001
Subject: Batch programming literature
Date: Wed, 10 Jan 2001 01:01:21
From: ts@uwasa.fi (Timo Salmi)

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.pressroom.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
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:22 2001
Subject: File's date and time
Date: Wed, 10 Jan 2001 01:01:22
From: ts@uwasa.fi (Timo Salmi)

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 information from 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, or look at the FAQ item #95.)

Let's also present a version where the file's datestamp is required
in the DD-MMM-YYYY HH:MM format:
  @echo off
  ::
  :: Check the input
  if "%1"=="" goto _usage
  if not exist %1 goto _nofind
  for %%f in (%1) do if "%%f"=="%1" goto _nowilds
  echo Don't use wildcards in the file name
  goto _end
  ::
  :: Put the file's information into a file
  :_nowilds
  dir %1 > dir$$$.tmp
  ::
  :: Get the information from 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 fileyear=" ; LTRIM$(MID$(a$,34,2))
  >> tmp$$$.bas echo PRINT #1, "set filemont=" ; LTRIM$(MID$(a$,31,2))
  >> tmp$$$.bas echo PRINT #1, "set fileday="  ; LTRIM$(MID$(a$,28,2))
  >> 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
  ::
  :: Adjust the year
  set ct_=20
  for %%y in (80 81 82 83 84) do if "%%y"=="%fileyear%" set ct_=19
  for %%y in (85 86 87 88 89) do if "%%y"=="%fileyear%" set ct_=19
  for %%y in (90 91 92 93 94) do if "%%y"=="%fileyear%" set ct_=19
  for %%y in (95 96 97 98 99) do if "%%y"=="%fileyear%" set ct_=19
  set fileyear=%ct_%%fileyear%
  ::
  :: Month as letters
  if "%filemont%"=="01" set filemont=Jan
  if "%filemont%"=="02" set filemont=Feb
  if "%filemont%"=="03" set filemont=Mar
  if "%filemont%"=="04" set filemont=Apr
  if "%filemont%"=="05" set filemont=May
  if "%filemont%"=="06" set filemont=Jun
  if "%filemont%"=="07" set filemont=Jul
  if "%filemont%"=="08" set filemont=Aug
  if "%filemont%"=="09" set filemont=Sep
  if "%filemont%"=="10" set filemont=Oct
  if "%filemont%"=="11" set filemont=Nov
  if "%filemont%"=="12" set filemont=Dec
  ::
  :: Show results
  echo %1 %fileday%-%filemont%-%fileyear% %filetime%
  ::
  :: Clean up
  for %%f in (dir$$$.tmp tmp$$$.bas tmp###.bat) do del %%f
  for %%v in (fileyear filemont fileday filetime ct_) do set %%v=
  goto _end
  ::
  :: Error messages
  :_usage
  echo Usage %0 Filename
  goto _end
  :_nofind
  echo File %1 not found
  ::
  :: End
  :_end
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:23 2001
Subject: Beep
Date: Wed, 10 Jan 2001 01:01:23
From: ts@uwasa.fi (Timo Salmi)

82. How would I get a beep in a batch file?
===========================================

This is simple. Insert into the batch file the line
  echo Ctrl+G
How to enter depends the control character depends on the editor you
are using. In MS-DOS Edit "Insert special characters" is done
applying the Ctrl+P,Ctrl+key combination. In other words, for the
beep you would enter the Ctrl+P,Ctrl+G combination.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:24 2001
Subject: Y2K old BIOS fix
Date: Wed, 10 Jan 2001 01:01:24
From: ts@uwasa.fi (Timo Salmi)

83. Y2K: My old BIOS gives a wrong year at boot. How can I fix it?
==================================================================

After the turn of the millennium an old BIOS may give dates like
2094 when the PC booted. If the date is otherwise correct, read on.
If the BIOS is not rewritable, or if you do not know how to rewrite
it, you still can utilize the following fix. (Incidentally, an old
BIOS that cannot be rewritten has at least one advantage. It is
safer from viruses than the modern ones.)
  @echo off
  rem
  rem A Y2K.BAT fix by Prof. Timo Salmi Sat 22-Jan-2000
  rem Useful for some old BIOSes which lose the year at boot
  rem To be called e.g. by the autoexec.bat
  rem Requires Timo's auxiliary batch GETDTE.BAT
  rem
  if "%1"=="" goto _usage
  call getdte.bat
  date %daynr_%-%monthnr_%-%1
  set weekday_=
  set daynr_=
  set monthnr_=
  set yearnr_=
  echo.| date | find "Current"
  echo.| time | find "Current"
  goto _out
  :_usage
  echo.
  echo Usage: Y2K Year
  echo.
  :_out

  @echo off
  rem GETDTE.BAT auxiliary batch by prof. Timo Salmi
  rem to extract date information for Y2K.BAT
  ::
  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 (99 00 01 02 03 04 05 06 07 08 09) do call %0 x x x %%d
  ::
  rem Clean up
  del tmp$$$.$$$
  :_end

As usual, there are several solutions to the same problem. One of
the alternatives is to use a QBASIC approach to set the day and
month number environment variables needed in the task.
  @echo off
  ::
  if "%1"=="" goto _usage
  ::
  :: A QBASIC program to create a batch for the date variables
  >  tmp$$$.bas echo LET a$ = DATE$
  >> tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "set mm_=" ; LTRIM$(MID$(a$,1,2))
  >> tmp$$$.bas echo PRINT #1, "set dd_=" ; LTRIM$(MID$(a$,4,2))
  >> 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
  ::
  :: Set and report
  date %dd_%-%mm_%-%1
  echo.| date | find "Current"
  echo.| time | find "Current"
  ::
  :: Clean up
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  set mm_=
  set dd_=
  goto _out
  ::
  :_usage
  echo.
  echo Usage: %0 Year
  echo.
  :_out
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:25 2001
Subject: Drop file name's first letter
Date: Wed, 10 Jan 2001 01:01:25
From: ts@uwasa.fi (Timo Salmi)

84. Is there a batch to drop the first letter of a file name?
=============================================================

The question is how one can rename XABC.TXT to ABC.TXT with a batch.
The demonstration solution below assumes that you have QBASIC
available. The principles used in the example can be adapted to
other, complicated file renaming tasks.
  @echo off
  ::
  :: If no parameter is given to the batch, show its proper usage
  if "%1"=="" goto _help
  ::
  :: Prepare a QBASIC program to detect the first character
  :: Handle different file name types like NAME.DAT NAME and .DAT
  echo LET n$="%1" > tmp$$$.bas
  echo LET p = INSTR(1, n$, ".") - 1 >> tmp$$$.bas
  echo IF p = 0 THEN LET b$ = "" >> tmp$$$.bas
  echo IF NOT (p=-1) AND NOT (p=0) THEN LET b$ = MID$(n$, 1, p) >> tmp$$$.bas
  echo LET b$ = MID$(n$, 1, 1) >> tmp$$$.bas
  echo LET c$ = MID$(n$, 2) >> tmp$$$.bas
  echo OPEN "tmp###.bat" FOR OUTPUT AS #1 >> tmp$$$.bas
  echo PRINT #1, "@echo off" >> tmp$$$.bas
  echo PRINT #1, "set first_=" + b$ >> tmp$$$.bas
  echo PRINT #1, "set rest_=" + c$ >> 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
  rem Remove the echo in the line below and you'll have your renaming
  if not "%rest_%"=="" echo ren %first_%%rest_% %rest_%
  goto _end
  ::
  :_help
  echo Usage %0 [NameToBeTruncated]
  ::
  :: Cleanup
  :_end
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  set first_=
  set rest_=

However, using an all-out batch method is not always the best
solution. Sometimes it is better to blend in a suitable text editor.
Like here we could have
  @echo off
  echo @echo off > doit.bat
  dir /b /l | find /v "doit.bat" >> doit.bat
After getting e.g.
  @echo off
  batfaq.bas
  testfngt.bas
  batfaq2.bat
  testadd.bat
  testfngt.bat
  batfaq.bat
you'd use the column handling of say
 978851 Feb 21 1997 ftp://garbo.uwasa.fi/pc/demo/tsedos25.zip
 tsedos25.zip The SemWare Editor Pro Test-Drive, good, nagware
to first duplicate the column:
  @echo off
  batfaq.bas   batfaq.bas
  testfngt.bas testfngt.bas
  batfaq2.bat  batfaq2.bat
  testadd.bat  testadd.bat
  testfngt.bat testfngt.bat
  batfaq.bat   batfaq.bat
Then the same method to remove the first letter:
  @echo off
  batfaq.bas   atfaq.bas
  testfngt.bas estfngt.bas
  batfaq2.bat  atfaq2.bat
  testadd.bat  estadd.bat
  testfngt.bat estfngt.bat
  batfaq.bat   atfaq.bat
And, finally you would use a keyboard macro to insert the ren to
complete your batch.
  @echo off
  ren batfaq.bas   atfaq.bas
  ren testfngt.bas estfngt.bas
  ren batfaq2.bat  atfaq2.bat
  ren testadd.bat  estadd.bat
  ren testfngt.bat estfngt.bat
  ren batfaq.bat   atfaq.bat
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:26 2001
Subject: Closing MS-DOS window
Date: Wed, 10 Jan 2001 01:01:26
From: ts@uwasa.fi (Timo Salmi)

85. How do I close the command window once my batch file has run?
=================================================================

Well this is a vanilla MD-DOS batch FAQ, but the solution is very
simple. Just put EXIT as the last line of your batch and the MS-DOS
box will close, if you are using Windows.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:27 2001
Subject: Re: Future of DOS batch files?
Date: Wed, 10 Jan 2001 01:01:27
From: ts@uwasa.fi (Timo Salmi)

86. Is MS-DOS batch programming going to die along with W2K?
============================================================

An edited extract from news:alt.msdos.batch
:I've heard via the grapevine that Windows 2000 won't run DOS
:programs.
:If that's the case, then are DOS files about to disappear into
:obscurity like CPM SUBMIT files?

Good question, but why would that be the case? I've said this often
before. The _relative_ number of W2K users is likely to grow
drastically, but if history is anything to go by, the absolute
number of MS-DOS users will not go down, maybe even the contrary.
The old PC base just is too large. This view is supported by the
observation that e.g. Garbo archive's MS-DOS section downloads are
on the level or higher than ever before, despite everything that has
happened on the PC / Windows scene. No, I do not expect MS-DOS batch
programming becoming extinct for quite a while. However, there
unfortunately continues to be an increasing number of incompatible
platforms, meaning an increasing fragmentation of skills and
knowledge, thanks to Microsoft's chosen paths.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:28 2001
Subject: Re: Testing for a substring
Date: Wed, 10 Jan 2001 01:01:28
From: ts@uwasa.fi (Timo Salmi)

87. How can I test for the existence of a substring in a string?
================================================================

>Timo
>I read your article on how to identify a computer via batch [item
>#35]. I have a similar problem, but i need to identify them with
>only part of a string
>  ex.: if NOT %COMPUTERNAME%==JV-CCI* GOTO END
>  where %COMPUTERNAME% is JV-CCI-1256
>wildcards like * does not seem to work, do you have another
>solution?

The problem can be solved with an auxiliary file and MS-DOS FIND:
  @echo off
  ::
  rem Set test strings for the demonstration
  set string_=WhateverLongString
  set subst_=Long
  ::
  rem Put the string into
  echo %string_% > tmp$$$
  ::
  rem Test for the existence of the substring
  find "%subst_%" tmp$$$ > nul
  if errorlevel==2 goto _2
  if errorlevel==1 goto _1
  goto _0
  ::
  rem The different outcomes
  :_0
  echo Match found
  goto _out
  :_1
  echo Match not found
  goto _out
  :_2
  echo Match not found, and error
  goto _out
  ::
  rem Clean up
  :_out
  if exist tmp$$$ del tmp$$$
  set string_=
  set subst_=
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:29 2001
Subject: Re: Getting find results
Date: Wed, 10 Jan 2001 01:01:29
From: ts@uwasa.fi (Timo Salmi)

88. How can I put MS-DOS FIND results into an environment variable?
===================================================================

This neat solution was presented by Tom Lavedas. Only minor
stylistic modifications have been made. The number of occurrences of
the search string is put into the found_ environment variable.
  @echo off
  if not exist m:\target.txt goto _nofile
  find /c "ZXZ" m:\target.txt > tmp$#$#$.bat
  echo set found_=%%2> ----------.bat
  call tmp$#$#$.bat ----------.bat
  echo %found_%
  if exist ----------.bat del ----------.bat
  if exist tmp$#$#$.bat del tmp$#$#$.bat
  set found_=
  goto _end
  :_nofile
  echo Target file not found
  :_end
If you wish to understand this batch, see what is contained in the
files tmp$#$#$.bat and ----------.bat during the process.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:30 2001
Subject: Unambiguous directory dates
Date: Wed, 10 Jan 2001 01:01:30
From: ts@uwasa.fi (Timo Salmi)

89. How to get months as letters and years in four digits in DIR?
=================================================================

Too difficult without auxiliary programs so first get
 20368 Oct 1 1991 ftp://garbo.uwasa.fi/pc/unix/sed15x.zip
 sed15x.zip HHSED executable, E.Raymond+D.Kirschbaum+H.Helman
Then you can use the following
  @echo off
  rem Display the directory with 4-digit years and months as letters
  rem Assumes a date format dd/mm/yy requiring in CONFIG.SYS e.g.
  rem COUNTRY=032,850,C:\DOS\COUNTRY.SYS
  ::
  :: Check that the Unix-like SED.EXE program is available
  set found_=
  if exist sed.exe set found_=yes
  for %%d in (%path%) do if exist %%d\sed.exe set found_=yes
  for %%d in (%path%) do if exist %%dsed.exe set found_=yes
  if "%found_%"=="yes" goto _continue
  echo sed.exe is not in the current directory or at path
  goto _out
  ::
  :: Make the substitutions
  :_continue
  dir %1 | find /v "TMP1$$$     " > tmp2$$$
  type tmp2$$$ | sed -e "s#/00  #/2000  #" -e "s#/9#/199#" -e "s#/8#/198#" > tmp1$$$
  type tmp1$$$ | sed -e "s#/01/#-Jan-#" -e "s#/02/#-Feb-#" > tmp2$$$
  type tmp2$$$ | sed -e "s#/03/#-Mar-#" -e "s#/04/#-Apr-#" > tmp1$$$
  type tmp1$$$ | sed -e "s#/05/#-May-#" -e "s#/06/#-Jun-#" > tmp2$$$
  type tmp2$$$ | sed -e "s#/07/#-Jul-#" -e "s#/08/#-Aug-#" > tmp1$$$
  type tmp1$$$ | sed -e "s#/09/#-Sep-#" -e "s#/10/#-Oct-#" > tmp2$$$
  type tmp2$$$ | sed -e "s#/11/#-Nov-#" -e "s#/12/#-Dec-#" > tmp1$$$
  ::
  :: Display the results
  type tmp1$$$
  ::
  :: Clean up
  :_out
  if exist tmp1$$$ del tmp1$$$
  if exist tmp2$$$ del tmp2$$$
  set found_=
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:31 2001
Subject: Future of MS-DOS batch files
Date: Wed, 10 Jan 2001 01:01:31
From: ts@uwasa.fi (Timo Salmi)

90. Isn't MS-DOS dead with W2K? So why bother with MS-DOS batches?
==================================================================

Good question, but why would that be the case? The _relative_ number
of Windows 2000 users is likely to grow drastically. But if history
is anything to go by, the _absolute_ number of MS-DOS users will not
go down, maybe even the contrary. The old PC base is just too large.
This is corroborated by the observation that e.g. Garbo archive's
MS-DOS section downloads are level or higher than ever before,
despite everything that has happened on the PC / Windows scene.
There are from 2000 up to 10000 MS-DOS related downloads from Garbo
MS-DOS archives each and every day. That's still far from dead even
if it is obvious that some quarters actively try to bury it.
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:32 2001
Subject: Stopping a called batch file?
Date: Wed, 10 Jan 2001 01:01:32
From: ts@uwasa.fi (Timo Salmi)

91. How can I exit the called batch without returning to the first?
===================================================================

 Q: "Batch1 calls Batch2.  On certain conditions I want Batch2 to
stop and not return control to Batch1. How can this be done?"

A: You can achieve the virtual EFFECT by the following kind of usage

  @echo off
  rem This file is BATFAQ.BAT
  set exit_=
  call batfaq2
  if "%exit_%"=="yes" goto _end
  echo We are now in the first batfaq
  :_end
  set exit_=

  @echo off
  rem This file is BATFAQ2.BAT
  echo We are now in the second batfaq2
  if [WhateverYourCondition] set exit_=yes
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:33 2001
Subject: Stopping a called batch file?
Date: Wed, 10 Jan 2001 01:01:33
From: ts@uwasa.fi (Timo Salmi)

92. How do I create a sequence of directories from 001 to MaxValue?
===================================================================

QBASIC is a very powerful additional batch tool which allows you to
program many things which would be overly complicated else. Below is
a batch solution utilizing QBASIC. For the demonstration it creates
the directories at the C:\TEMP directory. Customize as appropriate.
The same method is naturally applicable for other similar sequencing
tasks, as well.
  @echo off
  if "%1"=="" goto _usage
  ::
  if not exist C:\TEMP\nul mkdir C:\TEMP
  ::
  :: Build a QBASIC program to a file tmp$$$.bas
  >  tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "@echo off"
  >> tmp$$$.bas echo FOR I = 1 to %1
  >> tmp$$$.bas echo   LET i$ = LTRIM$(STR$(i))
  >> tmp$$$.bas echo   LET i$ = STRING$(3-LEN(i$),"0") + i$
  >> tmp$$$.bas echo   PRINT #1, "mkdir C:\TEMP\";i$
  >> tmp$$$.bas echo NEXT I
  >> 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
  goto _out
  ::
  :_usage
  echo Usage: %0 MaxValue
  :_out
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:34 2001
Subject: Performing calculations
Date: Wed, 10 Jan 2001 01:01:34
From: ts@uwasa.fi (Timo Salmi)

93. How do I add +1 to a variable in a batch?
=============================================

Again a QBASIC is the easiest solution even if there exist clever,
complicated other solutions.
  @echo off
  ::
  set number1_=145
  set add_=1
  ::
  :: Build a QBASIC program to a file tmp$$$.bas
  >  tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "@echo off"
  >> tmp$$$.bas echo LET i = %number1_% + %add_%
  >> tmp$$$.bas echo PRINT #1, "set number2_=";LTRIM$(STR$(i))
  >> 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
  ::
  echo The result of: add %number1_% +%add_% = %number2_%
  set number1_=
  set number2_=
  set add_=
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:35 2001
Subject: Errorlevel into a variable
Date: Wed, 10 Jan 2001 01:01:35
From: ts@uwasa.fi (Timo Salmi)

94. How to copy the errorlevel into a variable in a batch?
==========================================================

First let's recall the fundamental fact that batches do not return
errorlevels, program's do. So the question actually is "How do I
capture into a batch environment variable the errorlevel that an
executable program has returned?" Below is an example batch.
  @echo off
  echo +---------------------------------------------------+
  echo | A testbench for a program's errorlevel            |
  echo | Copyright (c) by Prof. Timo Salmi                 |
  echo | Email: ts@uwasa.fi  WWW: http://www.uwasa.fi/~ts/ |
  echo +---------------------------------------------------+
  echo.
  ::
  if "%1"=="" goto _help
  if exist %1 goto _continue
  if exist %1.com goto _continue
  if exist %1.exe goto _continue
  goto _notfound
  ::
  :_continue
  %1 %2 %3 %4 %5 %6 %7 %8 %9
  ::
  for %%i in (0 1 2 3 4 5 6 7 8 9) do if errorlevel==%%i set _el=%%i
  for %%i in (10 11 12 13 14 15 16) do if errorlevel==%%i set _el=%%i
  rem Add here all the missing, intervening rows yourself.
  for %%i in (250 251 252 253 254 255) do if errorlevel==%%i set _el=%%i
  echo Errorlevel==%_el%
  goto _out
  ::
  :_notfound
  echo File %1 not found
  goto _out
  ::
  :_help
  echo Usage ERRLEV ProgramName [Parameter1] [Parameter2] [...]
  ::
  :_out
  set _el=
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:36 2001
Subject: Zero byte file testing
Date: Wed, 10 Jan 2001 01:01:36
From: ts@uwasa.fi (Timo Salmi)

95. How can I test for a zero byte file?
========================================

There is more than one option to solve this. The classic method is
copying the file. A zero-length file will not copy.
  @echo off
  if "%1"=="" goto _help
  if not exist %1 goto _notfound
  copy %1 tmp$#$#$.$$$ > nul
  if not exist tmp$#$#$.$$$ echo File %1 is zero-length
  if exist tmp$#$#$.$$$ echo File %1 is not zero-length
  if exist tmp$#$#$.$$$ del tmp$#$#$.$$$
  goto :_out
  :_notfound
  echo File %1 not found
  goto :_out
  :_help
  echo Usage: %0 Filename
  :_out

A more refined method without the unnecessary overhead of the
copying is to compare the target file against the system's NUL file.
  @echo off
  if "%1"=="" goto _help
  if not exist %1 goto _notfound
  fc /b %1 nul | find "FC: no differences encountered" > nul
  if errorlevel==2 echo The batch failed
  if errorlevel==1 if not errorlevel==2 echo File %1 is not zero-length
  if errorlevel==0 if not errorlevel==1 echo File %1 is zero-length
  goto :_out
  :_notfound
  echo File %1 not found
  goto :_out
  :_help
  echo Usage: %0 Filename
  :_out

A third option is putting the file size into an environment variable
(size_) with a QBASIC program and then to test whether the size
equals zero.
  @echo off
  ::
  :: Check the input
  if "%1"=="" goto _usage
  if not exist %1 goto _nofind
  for %%f in (%1) do if "%%f"=="%1" goto _nowilds
  echo Don't use wildcards in the file name
  goto _end
  ::
  :: Put the file's information into a file
  :_nowilds
  dir %1 > dir$$$.tmp
  ::
  :: Get the information from 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 size enrironment variable
  :: Might require customizing depending on your configuration
  :: Do away with a possible points in the size
  >> tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #1
  >> tmp$$$.bas echo PRINT #1, "@echo off"
  >> tmp$$$.bas echo LET a$ = LTRIM$(MID$(a$,13,14))
  >> tmp$$$.bas echo FOR I = 1 TO 3
  >> tmp$$$.bas echo  LET p = INSTR(1, a$, ".")
  >> tmp$$$.bas echo  IF p = 0 THEN
  >> tmp$$$.bas echo   LET a$ = LTRIM$(MID$(a$,1,14))
  >> tmp$$$.bas echo  ELSE
  >> tmp$$$.bas echo   LET a$ = LTRIM$(MID$(a$,1,p - 1)) + LTRIM$(MID$(a$,p+1,14))
  >> tmp$$$.bas echo  ENDIF
  >> tmp$$$.bas echo NEXT I
  >> tmp$$$.bas echo PRINT #1, "set size_=" ; a$
  >> 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
  for %%f in (dir$$$.tmp tmp$$$.bas tmp###.bat) do del %%f
  ::
  :: Show (test) results
  echo %1 %size_% bytes
  if "%size_%"=="0" echo It is an empty file
  if not "%size_%"=="0" echo It is not an empty file
  ::
  :: Clean up
  set size_=
  goto _end
  ::
  :: Error messages
  :_usage
  echo Usage %0 Filename
  goto _end
  :_nofind
  echo File %1 not found
  ::
  :: End
  :_end
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:37 2001
Subject: Last N lines
Date: Wed, 10 Jan 2001 01:01:37
From: ts@uwasa.fi (Timo Salmi)

96. How to show the last N lines of a file using DOS batch files?
=================================================================

One could try a QBASIC solution in line with the other items in my
batch FAQ. Furthermore, innovative, but complicated batch-only
solutions have been suggested on the Usenet news. However, this is
one of the situations where a program ported from Unix to MS-DOS
makes a complicated task quite trivial. There are several TAIL
programs at Garbo program archive's directory of "Unix like MS-DOS
programs and material". The contents of the packages are listed in

 ftp://garbo.uwasa.fi/pc/unix/0unix.zip
 .zip files contents in /pc/unix directory

One of the several options is

 286909 Feb 17 1995 ftp://garbo.uwasa.fi/pc/unix/dosnx23b.zip
 dosnx23b.zip Dosnix Unix style MS-DOS utilities from G.Vrooman

You can also access the collections directly through WWW at
http://garbo.uwasa.fi/pc/unix.html

If you are not familiar with the tail program, the essentials are
its description "tail - deliver the last part of a file" and its
usage to display e.g. the last file lines of a file:
  tail -5 Filename
or
  type Filename | tail -5
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:38 2001
Subject: Locating and full path
Date: Wed, 10 Jan 2001 01:01:38
From: ts@uwasa.fi (Timo Salmi)

97. How do I get the path of a file located somewhere on my disk?
=================================================================

For a chosen drive:
  dir /s /b c:\file.xxx
For the default drive:
  dir /s /b \file.xxx

So far, so good. But what if you wish to perform some operations on
the file found. Say you wish to copy the first found match to the
m:\ root directory on your disk. This is how to go about it
  @echo off
  if "%1"=="" goto _help
  dir /s /b /l %1 > tmp$#$#$.dir
  ::
  :: Build a QBASIC program to a file tmp$$$.bas
  >  tmp$$$.bas echo OPEN "tmp$#$#$.dir" FOR INPUT AS #1
  >> tmp$$$.bas echo INPUT #1,a$
  >> tmp$$$.bas echo CLOSE #1
  >> tmp$$$.bas echo OPEN "tmp###.bat" FOR OUTPUT AS #2
  >> tmp$$$.bas echo PRINT #2, "@echo off"
  >> tmp$$$.bas echo PRINT #2, "copy "; a$; " m:\"
  >> tmp$$$.bas echo CLOSE #2
  >> 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
  if exist tmp$$$.bas del tmp$$$.bas
  if exist tmp###.bat del tmp###.bat
  if exist tmp$#$#$.dir del tmp$#$#$.dir
  goto :_out
  ::
  :_help
  echo Usage: %0 DriveLetter:\Filename
  ::
  :_out
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:39 2001
Subject: Locating and full path
Date: Wed, 10 Jan 2001 01:01:39
From: ts@uwasa.fi (Timo Salmi)

98. How to read a file's attributes into environment variables?
===============================================================

The QBASIC solution used many times throughout this FAQ can be
easily modified also for this task.
  @echo off
  ::
  :: Check the input
  if "%1"=="" goto _usage
  if not exist %1 goto _nofind
  for %%f in (%1) do if "%%f"=="%1" goto _nowilds
  echo Don't use wildcards in the file name
  goto _end
  ::
  :: Put the file's information into a file
  :_nowilds
  attrib %1 > dir$$$.tmp
  ::
  :: Get the informationfrom the file
  >  tmp$$$.bas echo OPEN "dir$$$.tmp" FOR INPUT AS #1
  >> tmp$$$.bas echo LINE INPUT #1, a$
  >> 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 arch_=" ; LTRIM$(MID$(a$,3,1))
  >> tmp$$$.bas echo PRINT #1, "set syst_=" ; LTRIM$(MID$(a$,6,1))
  >> tmp$$$.bas echo PRINT #1, "set hidd_=" ; LTRIM$(MID$(a$,7,1))
  >> tmp$$$.bas echo PRINT #1, "set rdon_=" ; LTRIM$(MID$(a$,8,1))
  >> 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
  ::
  :: Show results
  echo %1 %arch_% %syst_% %hidd_% %rdon_%
  ::
  :: Clean up
  for %%v in (arch_ syst_ hidd_ rdon_) do set %%v=
  goto _end
  ::
  :: Error messages
  :_usage
  echo Usage %0 Filename
  goto _end
  :_nofind
  echo File %1 not found
  ::
  :: End
  :_end
--------------------------------------------------------------------

From ts@uwasa.fi Wed Jan 10 01:01:40 2001
Subject: Echo -n
Date: Wed, 10 Jan 2001 01:01:40
From: ts@uwasa.fi (Timo Salmi)

99) Is it possible to echo without linefeed like the Unix echo -n?
==================================================================

Let's be unorthodox, and not attempt a strict batch only solution.
If you have a suitable compiler you can program an echon.exe command
to do the equivalent of the Unix echo -n. E.g. in Turbo Pascal all
ECHON.PAS takes is
  type CommandLineType = string[127];
  var  CommandLinePtr  : ^CommandLineType; s : string; i : byte;

  begin
    CommandLinePtr := Ptr(PrefixSeg, $80);
    s := CommandLinePtr^;
    for i := 2 to Length(s) do write (s[i]);
  end.
If you do not have a TP compiler, you can get an old
 981 Nov 13 1987 ftp://garbo.uwasa.fi/pc/batchutil/echon.zip
 echon.zip MS-DOS echo command without the CR/LF
Furthermore, debug-based solutions have been presented in the
news:alt.msdos.batch newsgroup.

In the batch you might have e.g. something like
  @echo off
  echon Working...
  pkzip test.zip test.bat > nul
  echo  done
--------------------------------------------------------------------

