1) The Batch language is particularly good for producing lists
Many batch commands produce useful lists that can be redirected to a file.
For example, DIR with the /b switch (=bare list of filespecs) and XCOPY
with /l (that's the L=list only switch, available in Windows 95/98/ME GUI).
DIR C:\*.TMP /b/s/a-d>TMPLIST
xcopy C:\*.TMP C:\ /l/s/h/n/y>TMPLIST
(At the prompt, type "DIR /?" or "XCOPY /?" for brief help on the switches)
Both of these produce lists of files with extension TMP on the C: drive.
The DIR method produces an incomplete list (since DIR doesn't search within
hidden or system folders), and each item starts with the drive spec. The
XCOPY method produces a complete list and leaves off the drive spec (which
is an advantage, as we'll see below), but includes the rest of the path. With
the /n switch it gives lists in short-name alias format (=8.3 format for folder
and file names), which can also be an advantage.
2) Processing such lists
Suppose you wish to "process" such a list, for example by deleting all the
file specifications it produces? One way is to prefix each line of the list
with DEL[Space], give the list a .BAT file name, and CALL it: then this
(temporary) Batch file will carry out all the deletions (and can itself be
deleted afterwards).
To see how this prefixing might be done, consider a simple list in a file
called LIST.BAT consisting of the two items:
FileSpecOne
FileSpecTwo
If you execute this as a Batch file, not much appears to happen (unless
by some chance, "FileSpecOne" or "FileSpecTwo" happen to be valid
commands on your system).
============Screen capture
C:\WORK>list.bat
C:\WORK>FileSpecOne
Bad command or file name
C:\WORK>FileSpecTwo
Bad command or file name
C:\WORK>
C:\WORK>
============End screen capture
Each "command" just "bounces" off the prompt (_without_ being executed) and
produces a "Bad command or file name" error. However, you can capture the
resulting action in a file by executing LIST.BAT in a COMMAND /c child shell.
============Screen capture
C:\WORK>command /c list.bat>PREFIX.BAT
Bad command or file name
Bad command or file name
C:\WORK>
============End screen capture
Notice that only the "Bad command or file name" (which goes to STDERR=
standard error message device) is now seen, and the rest (which goes to
STDIN=standard input device) is redirected to PREFIX.BAT which is now:
============Screen capture (items in parentheses added as notes)
C:\WORK>type prefix.bat
C:\WORK>FileSpecOne (this is a line in PREFIX.BAT)
C:\WORK>FileSpecTwo (this is a line in PREFIX.BAT)
C:\WORK> (this is a line in PREFIX.BAT)
C:\WORK>
============End screen capture
If you change the system PROMPT to say DEL+[Space], then this happens:
============Screen capture
C:\WORK>prompt DEL (there is a [Space] after DEL)
DEL list.bat (prompt is now DEL+[Space], type LIST.BAT at prompt)
DEL FileSpecOne (now the bounce includes DEL+[Space])
Bad command or file name
DEL FileSpecTwo
Bad command or file name
DEL
DEL prompt $p$g (reset prompt to normal)
C:\WORK>
============End screen capture
The command to reset the PROMPT can be placed at the front of LIST.BAT (it
needs the @ prefix, since we don't want to ECHO the PROMPT change command
itself). If we change LIST.BAT to consist of:
============Screen capture
C:\WORK>type list.bat
@PROMPT DEL (there is a [Space] after DEL)
FileSpecOne
FileSpecTwo
C:\WORK>
============End screen capture
Then when run in a /c child shell, you get this output
============Screen capture
C:\WORK>command /c list.bat
DEL FileSpecOne
Bad command or file name
DEL FileSpecTwo
Bad command or file name
DEL
C:\WORK>
============End screen capture
and when captured in PREFIX.BAT you get this
============Screen capture
C:\WORK>command /c list.bat>PREFIX.BAT
Bad command or file name
Bad command or file name
C:\WORK>type prefix.bat
DEL FileSpecOne
DEL FileSpecTwo
DEL
C:\WORK>
============End screen capture
PREFIX.BAT has a spurious DEL line at the end. This can be removed by
adding @ECHO OFF to the end of LIST.BAT before "bouncing" it.
So if LIST.BAT consists of
@PROMPT DEL
FileSpecOne
FileSpecTwo
@ECHO OFF
then you get this:
============Screen capture
C:\WORK>command /c list.bat
DEL FileSpecOne
Bad command or file name
DEL FileSpecTwo
Bad command or file name
C:\WORK>command /c list.bat>PREFIX.BAT
Bad command or file name
Bad command or file name
C:\WORK>type prefix.bat
DEL FileSpecOne
DEL FileSpecTwo
C:\WORK>
============End screen capture
And PREFIX.BAT is the prefixed list. Putting that together into a batch
script gives this:
====Begin cut-and-paste (omit this line)
@ECHO OFF
:: Start with the PROMPT command for the required prefix
ECHO.@PROMPT DEL >LIST.BAT
:: Append the list (this is purely a demo)
ECHO.FileSpecOne>>LIST.BAT
ECHO.FileSpecTwo>>LIST.BAT
:: Append the @ECHO OFF
ECHO.@ECHO OFF>>LIST.BAT
:: Prefix the list with the PROMPT
%COMSPEC%/c LIST.BAT>PREFIX.BAT
====End cut-and-paste (omit this line)
To use the code above, cut-and-paste the text between the ==== lines
into a file with extension .BAT and base name of your choice. Lines
that don't begin with two spaces have wrapped in transmission.
And PREFIX.BAT is now a temporary Batch script that when CALLed will
process the list according to whatever temporary PROMPT you set.
That's all there is to it - except for the problems!
The problems:
===Problem 1) The "Bad command or file name" messages
There will be one of these for each line of the list to be processed. They
show that the list has "bounced" as intended, but it's convenient to remove
them. The traditional way is to use CTTY NUL (to turn off all messages,
and, NOTE THIS, keyboard input as well) and CTTY CON to turn them back on
again. Because CTTY NUL turns off keyboard input, you need to make sure the
CTTY CON turns it on again before the script ends:
====Begin cut-and-paste (omit this line)
@ECHO OFF
:: Start with the PROMPT command for the required prefix
ECHO.@PROMPT DEL >LIST.BAT
:: Append the list (this is purely a demo)
ECHO.FileSpecOne>>LIST.BAT
ECHO.FileSpecTwo>>LIST.BAT
:: Append the @ECHO OFF
ECHO.@ECHO OFF>>LIST.BAT
:: Prefix the list with the PROMPT
CTTY NUL
%COMSPEC%/c LIST.BAT>PREFIX.BAT
CTTY CON
====End cut-and-paste (omit this line)
To use the code above, cut-and-paste the text between the ==== lines
into a file with extension .BAT and base name of your choice. Lines
that don't begin with two spaces have wrapped in transmission.
This method produces a spurious blank line in the display as the CTTY
commands are executed. You can back up one line and hide this if ANSI.SYS
is loaded. However, a useful alternative method (that doesn't need ANSI.SYS)
is to put the prefixing code line in a Subroutine, and call it in a NUL/c shell:
====Begin cut-and-paste (omit this line)
@ECHO OFF
IF (GOTO:)==(%1) %1%2 (Subroutine handler)
:: Start with the PROMPT command for the required prefix
ECHO.@PROMPT DEL >LIST.BAT
:: Append the list (this is purely a demo)
ECHO.FileSpecOne>>LIST.BAT
ECHO.FileSpecTwo>>LIST.BAT
:: Append the @ECHO OFF
ECHO.@ECHO OFF>>LIST.BAT
:: Call the Prefix subroutine in a NUL/c shell to suppress messages
%COMSPEC% NUL/c %0 GOTO: _PREFIX
GOTO EOF (=Subroutine code follows=)
:_PREFIX
%COMSPEC%/c LIST.BAT>PREFIX.BAT
:EOF (End-of-file)
====End cut-and-paste (omit this line)
To use the code above, cut-and-paste the text between the ==== lines
into a file with extension .BAT and base name of your choice. Lines
that don't begin with two spaces have wrapped in transmission.
In practice, the files PREFIX.BAT and LIST.BAT could be created in your TEMP
folder to avoid the need to write clutter to the current folder. And, of course, you
would include a line to CALL PREFIX.BAT to do the job of processing the list.
And commands to delete both LIST.BAT and PREFIX.BAT as the script ends.
===Problem 2) One of the items is a command in the PATH
The key principle of the PROMPT bounce method is that each line should
_bounce_ as a bad command, and not _execute_ as a good one. But suppose
one or more of the lines happens to be a valid command in the system
PATH? Then they won't bounce, they'll be executed, and create havoc.
The usual workaround for this is to (temporarily) save the system PATH,
clear it, and then do the bounce, then restore the PATH. This way, no
commands in the PATH will be found during the bounce operation.
===Problem 3) One of the items is a command in the current folder
Of course, if one of the list items is a valid command in the current
folder, clearing the PATH won't help stop its being executed. So it
still won't bounce correctly.
The usual workaround for this is to (temporarily) create an empty folder,
make that folder current, do the bounce (in the empty folder), then
return to current folder afterwards.
For a demo using both Problem 2 and 3 workarounds, see Note 1.
===Problem 4) One of the items is an internal command
Suppose LIST.BAT consists of:
@PROMPT DEL
FileSpecOne
FileSpecTwo
pause
@ECHO OFF
When you try to bounce it off the PROMPT (which will look like DEL ) the
"pause" won't bounce, it will be executed and stall the process like this:
============Screen capture
C:\WORK>command /c list.bat
DEL FileSpecOne
Bad command or file name
DEL FileSpecTwo
Bad command or file name
DEL pause
Press any key to continue . . .
============End screen capture
The workaround is to make sure this doesn't happen, by configuring the list
to avoid the possibility. Often, you will know the list won't contain such
items. For other occasions, you need to use ingenuity in constructing the
list. See problem 5 for more details on the workarounds.
===Problem 5) Some items are fully-qualified executable filespecs
With DIR /b /s listings of executables, the list will consist of full file
specifications. So neither clearing the path, nor working in an empty
folder will help. For example, if (with Windows 95/98/ME) LIST.BAT
consists of:
@PROMPT DEL
FileSpecOne
FileSpecTwo
C:\WINDOWS\COMMAND\choice.com
@ECHO OFF
then the choice.com line won't bounce properly, it will stall:
============Screen capture
C:\WORK>command /c list.bat
DEL FileSpecOne
Bad command or file name
DEL FileSpecTwo
Bad command or file name
DEL C:\WINDOWS\COMMAND\choice.com
[Y,N]?
============End screen capture
The workaround for both problems 4 and 5 is to prevent the problem
happening in the first place. Two methods I've published before:
(a) SUBST a spare drive letter.
For DIR lists, you can temporarily SUBST an unused drive letter, say P, to
produce the list (then all the drive specs will be P:\) and then cancel the
substitution for the bounce, then restore it while processing the list. I
published a working demo of this technique recently (see Note 2 below).
This technique avoids all the problems 2, 3, 4, and 5.
(b) Use XCOPY /L listings
XCOPY /L (=list only) listings are more PROMPT-bounce "friendly" in that
they can often be configured to avoid all the problems 2, 3, 4, and 5
without needing any of the workarounds at all. I've published several
recent examples of this. For the most flexible technique I've discovered
so far, see Note 3 below.
===Problem 6) Some items contain % characters
When the list items contain % characters, the PROMPT-bounce processing will
attempt to interpret them in the normal Batch way: single % characters may
be lost, pairs of %'s will be reduced to single % characters, and text
delimited by % characters may be interpreted as environment variables.
This will corrupt the item in the resulting processed list.
Workarounds for this include using SED to amend the list, or do the
prefixing entirely (see note 4); or using the Microsoft CSCRIPT batch
interface to amend the list or do the prefixing entirely (see Note 5).
Either of these will avoid the usual % interpretation (CSCRIPT can
have % interpretation turned ON and OFF as you please).
--
William Allen
Note 1
Demo of PATH cancel and empty folder working for PROMPT-bounce
From: "William Allen"
Newsgroups: alt.msdos.batch
Subject: Re: batch file to search drives
Date: Fri, 16 Nov 2001 06:54:54 -0000
Message-ID: <9t2d9c$16kc4c$2...@ID-55970.news.dfncis.de>
Note 2
Working demo of SUBST technique for PROMPT-bounce prefixing:
From: "William Allen"
Newsgroups: alt.msdos.batch
Subject: Re: attrib - wildcards with folders
Date: Sat, 10 Nov 2001 19:15:16 -0000
Message-ID: <9sjubl$12g90v$2...@ID-55970.news.dfncis.de>
Note 3:
Running FOR IN DO on all subfolders of a particular folder with XCOPY /L
cyclic error suppression:
From: "William Allen"
Newsgroups: alt.msdos.batch
Subject: FOR IN DO loop executed in all subfolders
Date: Fri, 16 Nov 2001 21:15:08 -0000
Message-ID: <9t3vsf$93vo$1...@ID-55970.news.dfncis.de>
You can read old Usenet posts at:
http://groups.google.com/advanced_group_search
Note: Google search by Message-ID is usually the quickest.
The Message-ID is the identifier in the <angle> brackets.
Simply cut-and-paste the Message-ID into Google page above.
Note 4:
Windows compatible version of SED (the Stream EDitor) freeware from:
ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/sed302b.zip
ftp://ftp.cdrom.com/.27/simtelnet/gnu/djgpp/v2gnu/sed302b.zip
source-code-inclusive version
ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/sed302s.zip
ftp://ftp.cdrom.com/.27/simtelnet/gnu/djgpp/v2gnu/sed302s.zip
Note 5:
CSCRIPT.EXE is a first-party (Microsoft) Batch file interface for
Windows 95/98/ME, installed with WSH (Windows Script Host):
Windows Script Host main page for information:
http://msdn.microsoft.com/scripting/
Which batch language would that be? Is that DOS batch or
William Allen batch?
--
<!-Outsider//->
MS-DOS 6.22, Windows for Workgroups 3.11, Netscape Communicator 4.08
I should have mentioned that, because the LIST.BAT script
is run in a child shell, the PROMPT change it makes is lost
again when the script ends and the child shell closes. That's
why there is no need to restore the prompt again when using
this prefix method. Your original prompt returns automatically,
as shown above.
--
William Allen