Assorted Batch Tricks                               Sat 8-May-1993
=====================
                                             (All rights reserved)

..................................................................
Prof. Timo Salmi      Co-moderator of comp.archives.msdos.announce
Moderating at garbo.uwasa.fi anonymous FTP archives 128.214.87.1
Faculty of Accounting & Industrial Management; University of Vaasa
Internet: ts@uwasa.fi Bitnet: salmi@finfun   ; SF-65101, Finland
..................................................................

  Ŀ
   This file belongs to TSBAT*.ZIP. Please do not distribute 
   this batricks.txt file separately.                        
  

Introduction
============

This file contains assorted batch tricks. 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.


INDEX
=====

1)  Making "@echo off" general
2)  Deleting all files
3)  Nested loops
4)  Checking whether a directory exists
5)  Checking that a program is available at the current directory or at path
6)  Using subroutines in batches
7)  Convert a parameter to uppercase
8)  Appending a new directory to the path
9)  Comparing two files
10) Writing an empty line
11) Customizing the pause message
12) Complicate renaming with for
13) Checking for wildcards
14) Preventing breaking the batch
15) Prevent a break from bypassing your autoexec.bat
16) Getting the extension
17) The quote character %
18) Eliminating auxiliary batches
19) Utilizing the subst command in paths
20) How to run a batch once a week (testing for the weekday)
21) Testing if a file name includes a path
22) Showing the time without enter
23) Alternatives for testing for the errorlevel value
24) Redirecting a batch file's output
25) Testing for environment space sufficiency
26) A simple trick to "disable" a drive
27) Sending an escape sequence to the printer
28) Creating a random string
29) Finding out the lenght of a string
30) How to obtain the MsDos version into an environment variable
31) Finding out the number of regular files on a drive
32) Augmenting line numbers to a text file
33) Storing and returning to the original directory (push and pop)
34) Enticing the current date into an environment variable
35) Identifying the individual PC
36) For loop and redirection quirks


1. Making "@echo off" general
=============================

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 MsDos
version 3.30.  So if you want to make it general, put the following
line in your autoexec.bat file if you are using MsDos 3.30 or higher
 set _echo=@
Then use the following format in your batches, which will then work
for any MsDos version
 %_echo%echo off


2. Deleting all files
=====================

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
Whether or not it is sensible to suppress the confirmation can be
debated, but this is the trick anyway.


3. Nested loops
===============

It is possible to have nested loops of a kind in batch programming.
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
  for %%g in (1 2 3) do echo %1%%g

Alternatively write everything 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.


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


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


6. Using subroutines and recursion in batches
=============================================

It is possible to use subroutines within batches. The crucial trick
is setting an environment variable (eg _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 go 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 zeroeth
parameter of a batch file points to itself.


7. Convert a 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 MsDos 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_%

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


8. Appending 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 MsDos 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.


9. Comparing two files
======================

It is possible in batch programming to test whether or not two files
have identical contents. This trick utilizes th external MsDos
programs fc.exe and find.exe.  (An external MsDos program means, of
course, a program that comes with the standard MsDos releases. Most
often the MsDos external support files are located in a c:\dos
directory.)
  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.


10. Writing an empty line
=========================

This is a simple, but an often needed, useful trick.  Just use echo
with (for example) a point (.) after it. As you can see, I have
utilized this batch feature extensively in my batch collection.
 echo.


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


12. Complicate renaming with for
================================

Although this is basically trivial, one does not necessarily come to
thing 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 30 instead of 29.
  tspa2940.zip
  tspa2950.zip
  tspa2955.zip
  tspa2960.zip
  tspa2970.zip
The following for-statement does that conveniently.
 for %f in (40 50 55 60 70) do ren tspa29%f.zip tspa30%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:


13. Checking for wildcards
==========================

This example shows how you can 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


14. Preventing breaking the batch
=================================

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.
  @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 garbo.uwasa.fi:/pc/ts/
tstsr16.zip (or whichever version number is current).


15. Prevent a break from bypassing your 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 comp.os.msdos.programmer newsgroup by
Joseph Gil yogi@cs.ubc.ca.

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


16. Getting the extension
=========================

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


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


18. Eliminating auxiliary batches
=================================

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


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


20. How to 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 MsDos 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?


21. Testing if a file name includes a path
==========================================

First of all please see the earlier item "Getting the extension"
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_=


22. Showing the time without 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.


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

Many programs and some MsDos 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.


24. Redirecting a batch file's output
=====================================

Output from within a batch file is easily redirected. Consider a
batchfile 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 batchfile 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.


25. Testing for environment space sufficiency
=============================================

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


26. A simple trick to "disable" 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


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


28. Creating a ramdom string
============================

I was asked on the UseNet news how to create a ramdom 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 ramdom_=";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


29. Finding out the lenght of a string
======================================

The task of finding out the lenght of a string was tackled in PC
Magazine January 26, 1993 issue. The solution is my own and more
general, but naturally it has simlar ingredients to the PC
Magazine's.
  @echo off
  set test_=Testing the lenght 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 lenght is %length_% bytes
  del len$&$&$
  del len$&$&$.bat
  del go$$$.bat


30. How to obtain the MsDos version into an environment variable
================================================================

If you look at for example ADJCURS.BAT you'll see how to test for
the MsDos version by batch commands only. Here is an alternative
method.
  @echo off
  ver > go$$$.bat
  echo @echo off> ms-dos.bat
  echo set version_=%%2>> ms-dos.bat
  call go$$$
  echo Your MsDos version is %version_%
  del go$$$.bat
  del ms-dos.bat


31. Finding out the number of regular files on a drive
======================================================

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


32. Augmenting line numbers to a text file
==========================================

Occasionally it might be useful to put line number to a text file.
Here is an example how to do it with MsDos commands only
  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.


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

There are several methods for (non-resident) pushing and popping the
directory by bacth 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 sencond method, displayed below, is a
direct adaptation from Jeff Prosise's column in PC Computing, March
1993, pp. 216-217. The method is a very clever utilization of the
prompt system. An example illustrates.

  @echo off
  echo @prompt cd $p$_$n:> r:\setback.bat
  %comspec% /c r:\setback> r:\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 r:\goback
  echo Now back in the orginal directory
  ::
  rem cleanup
  if exist r:\setback.bat del r:\setback.bat
  if exist r:\goback.bat del r:\goback.bat


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> r:\tmp$$$.bat
  %comspec% /c r:\tmp$$$> r:\tmp2$$$.bat
  call r:\tmp2$$$
  echo %date_%
  del r:\tmp$$$.bat
  del r:\tmp2$$$.bat

If you look at your MsDos 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. Execise: Put the current weekday into an
environment variable. Hint: Apply $d and $h.


35. Identifying the individual PC
=================================

In cases of some batches it is useful to identify the PC the batch
is run on. For example I use several different PCs myself and
occasionally I need to differentiate between them. The solution is
really trivial. Set an environement variable in the autoexec.bat to
designate the PC. I use a variable pcid_ for this purpose. An
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


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

A question from Newsgroups: comp.os.msdos.misc,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
> everytime when I use a conditional statment 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
