Dear friends of batch programming,
This chapter describes some undocumented features of the command.com which comes with Windows 98, 96360 Bytes, Friday, May 15, 1998

Switches

Parameters

Commands:
ECHO
CALL
FOR
GOTO
IF
IF EXIST

Last update on Sunday, April 20, 2003


Switches

The help text command /? describes the /P, /Y, /K and /C switches only. There are some more:

/F makes all "Abort, Retry, Ignore, Fail?" disk error messages default to "Fail":
command /F/K dir a: %try without floppy disk%
command /F/C dir a: %try without floppy disk%

command /P executes the autoexec.bat but command /P/K doesn't.
command /P/C echo does the same as command/C echo

/T supresses the EXIT command (similar to /P):
command /T echo doesn't execute the autoexec.bat
command /T/K echo does the same as command /P/K
Dangerous: command /T/C causes a break down.

/Z shows the errorlevels of extern commands:
command /Z/K move nul con
command /Z/C for %%T in (con nul) do move nul %%T
command /Z/Y/K move nul con

/D   I don't know what it does. I guess it means "default".
command /D/C echo
command /D/K echo



Parameters

Delimiter ; , = and whitespace
Example: showpar one,two;three=four five
where showpar.bat has the line
@echo %%0=%0 %%1=%1 %%2=%2 %%3=%3 %%4=%4 %%5=%5 %%6=%6 %%7=%7 %%8=%8 %%9=%9

Quotes
Words between quotes are treated as one parameter:
showpar "one two three"
A Delimiter between quotes is treated as a parameter:
showpar " "   ", ="   "=; "
An empty string between quotes as a parameter:
showpar ""
It is possible to eliminate quotes with FOR.

Putting many parameters in one parameter using a single quote:
some.bat "this is only one parameter
and some.bat eliminates the quotes and separates the parameters with FOR:
:: some.bat
for %%T in ("%1) do echo %%T

Using a single quote to append additional words to a parameter:
:: append.bat
showpar "%1 + some more words



Commands

ECHO

Delimiter , ; = :
for %%T in ("," ";" "=" :) do echo%%T   echoes an empty line
for %%T in (",off" ";on" "=off" :on) do echo%%T   turns the ECHO off and on
for %%T in ("," ";" "=" :) do echo%%Toff limits   echoes OFF
for %%T in ("," ";" "=" :) do echo%%Ton demand   echoes ON

Delimiter + . [ ] \ / "
for %%T in (+ . [ ] \ /) do echo%%T   echoes an empty line
for %%T in (+off .on [off ]on \off /on) do echo%%T   echoes the words "off" and "on"
for %%T in (+ . [ ] \ /) do echo%%Toff limits   echoes off limits
for %%T in (+ . [ ] \ /) do echo%%Ton demand   echoes on demand

Hide the first quote:
echo"this is no pipe: | "


CALL

CALL>file without parameters captures the PROMPT (without launching a separate DOS shell!).
Example:
:: _DATE.BAT written by Hermann Fritz 06.11.02
@prompt set date$Q$D
@echo on

@CALL>%temp%.\~tmp.bat

@echo off
prompt $p$g
for %%T in (call del) do %%T %temp%.\~tmp.bat

Important is the empty line after CALL

CALL<file without parameters in the last line of a batch process executes the fist line of a file.
Example:
:: DATE_.BAT written by Hermann Fritz 09.11.02
@prompt for %%T in (del:%%temp%%.\text ctty:con "set date$Q$D") do %%T$_
@call>%temp%.\text
prompt $P$G
@ctty nul
@CALL<%temp%.\text

The imported text is not treated as a part of the batch program. It is treated as the first command after the batch program. Therefore ctty nul

Instead of call you may also use if A==A; or if errorlevel 0; (don't forget the semicolons) or if exist nul or if exist con


FOR

Variable

whitepace and , ; = / > < | between quotes:
for %%" " in (some) do echo %% thing
for %%"," in (something) do echo %%,
for %%"/" in (something) do echo %%/
for %%"<" in (something) do echo "%%<"

Group

quotes allowe whitespace in an expression:
for %%T in (" ") do %%T causes an empty line
for %%T in ("set variable=" "echo The number is ") do %%T440
Example: capturing the PROMPT:
command /C for %%T in (" ") do %%T>~tmp.bat
Example:
set variable=first%%Tsecond
for %%T in (" echo " " set variable=") do if not ""==%variable%

Example: cutting off the first character:
for %%4 in ("set variable=" echo:) do %%4567
Example: cutting off leading zeros:
::cut0.bat
@echo off
set number=%1
:loop
if not _%number%==_0 for %%0 in (" set number=" " goto loop ") do if not exist \\%%%number%
if _%number%==_ echo Syntax: cut0 number
if not _%number%==_ echo number=%number%

The empty string is not processed:
for %%T in ("") do echo %%Tnothing   does nothing

for %%T in (()  do echo %%T   echoes (
for %%T in ( )) do echo %%T   echoes )
for %%T in ())  do echo %%T   does nothing

for %%T in (")")  do echo %%T   does nothing
for %%T in ( ")") do echo %%T   echoes )
for %%T in (" )") do echo %%T   echoes   )

for %%T in (1)his) do echo %%T   echoes 1)his
for %%T in (1) his) do echo %%T   Syntax Error

Delimiter , ; = whitespace
for %%T in (one two,three;four=five) do echo %%T
Example: getting the last word:
set variable=two words
for %%T in (%variable%) do set var=%%T

Very curious: The first delimiter after the empty string is processed:
for %%T in ( ""=;,) do echo %%T476   echoes =476

Special delimiter /
for %%T in (anything/234/5$) do echo %%T

suppressing the effect of quotes and wildcards:
for %%T in (/"/*/???) do echo %%T
converting a word to uppercase:
for %%T in (/word) do echo %%T
Example:
::UPPERCAS.BAT
@echo off
set UP=
:UP Written by Hermann Fritz 22.2.2002, http://www.unet.univie.ac.at/~a7425519/programme/
for %%T in (/%1) do set UP=%UP%%%%%T
if not _%2==_ for %%T in (shift goto) do %%T UP
for %%"/" in (" ") do set UP=%UP%
for %%" " in ("set UP=" echo:) do %%%UP%
if _%1==_ echo Converts words to UPPERCASE and puts them into the variable "UP".
if _%1==_ echo Usage: %0 some words

Using IF to prevent redirection < >
Redirection is not executed in following cases:
if 0==0 for %%T in (true"<":) do echo %%T echoes true
if exist nul for %%T in (true"<":) do echo %%T echoes true
if errorlevel 0 for %%T in (true"<":) do echo %%T echoes true
Redirection is executed in this case:
for %%T in (true"<":) do echo %%T File not found

Wildcards
*.* means All Files. All the other wildcards have a very different effect after turning on LFNFOR.

With LFNFOR OFF (default) FOR looks for short names and gives a short name output:
for %%T in (*.*) do echo %%T   finds all files.
for %%T in (* or *.) do echo %%T   finds filenames without extension.
How to find all filenames with extension?
for %%T in (*.*) do if not exist %%T.* echo %%T   works in most cases but it doesn't find index.htm if there is a index.htm.gz in the same directory.
for %%T in (????.??) do echo %%T   finds filenames with 1-4 characters + extensions with 0-2 charakters.
for %%T in (????) do echo %%T   finds filenames without extension with 1-4 characters.
for %%T in (.*) do echo %%T   finds finds nothing.
for %%T in (*.*.*) do echo %%T   finds finds nothing.

After LFNFOR ON (optional, it doesn't work in the pure DOS modus) FOR looks for both long and short names using the same criteria as IF EXIST.
FOR gives a long name output:
for %%T in (*.* or *) do echo %%T   finds all files.
for %%T in (.*) do echo %%T   finds filenames without stem like ".EXT".
for %%T in (*.) do echo %%T   finds filenames without extension.
for %%T in (*.?*) do echo %%T   finds filenames with extension.
for %%T in (*.*.*) do echo %%T   finds filenames with two or more dots: "A.B.C", even "..G"-or "GH..GH".
for %%T in (????.??) do echo %%T   finds stems with 4 characters + extensions with 2 charakters.
for %%T in (????) do echo %%T   finds filenames with 3-4 characters.
How to find all filenames with exact 4 characters? - I don't know.


GOTO

Long Labels
Normally the GOTO command uses the leading eight characters of the label only:
goto 12345678something jumps to :12345678 as well as to :12345678anything
But if the GOTO command contains a dot, labels up to 11 characters are effective:
goto 12345678anything.a
goto 12345678anything.ab
goto 12345678anything.abc
goto 12345678anything.abcd
jump to :12345678abc but not to :12345678
goto 12345678anything
goto 12345678anything.a
goto 12345678anything.ab
jump to :12345678ab or :12345678abc
Before the dot there must be at least 8 characters. Otherwise the dot has no effect:
goto 0000.1 jumps to :0000
A second dot has no effect:
goto 12345678.abcd.xxx jumps to :12345678abc
goto 123456789..abc jumps to :12345678

Wildcard *
goto * jumps to :????????
goto a* jumps to :a???????
goto ab* jumps to :ab??????
goto a?b* jumps to :a?b?????

goto *.* jumps to :???????????

goto *a and goto *aa jump to :????????
goto **a and goto **aa and goto *a*a jump to :????????

Delimiter

First Delimiter , : ; = and + . [ \ ] but not /
goto first second jumps to :first
goto,first second jumps to :first
goto;first second jumps to :first
goto=first second jumps to :first
goto:first second jumps to :first
goto+first second jumps to :second
goto.first second jumps to :second
goto[first second jumps to :second
goto\first second jumps to :second
goto]first second jumps to :second
goto/first second label not found
Example: goto+%var% end jumps to the second word of %var% or it jumps to :end if %var% has no second word.

Whitespace after the First Delimiter , ; = + . : [ \ ] but not /
goto, first jumps to :first
goto; first jumps to :first
goto= first jumps to :first
goto: first jumps to :first
goto+ first jumps to :first
goto. first jumps to :first
goto[ first jumps to :first
goto\ first jumps to :first
goto] first jumps to :first
goto/ first label not found

Second Delimiter , ; = " + : but not . / [ \ ]
goto ,first second jumps to :first
goto ;first second jumps to :first
goto =first second jumps to :first
goto "first second" jumps to :first
goto +first second jumps to :first
goto .first second label not found
goto :first second jumps to :first
goto /first second label not found
goto [first second label not found
goto \first second label not found
goto ]first second label not found

Whitespace after the Second Delimiter , ; = but not + . : / [ \ ]
goto , first second jumps to :first
goto ; first second jumps to :first
goto = first second jumps to :first
goto " first second" jumps to :first
goto + first second label not found
goto . first second label not found
goto : first second label not found
goto / first second label not found
goto [ first second label not found
goto \ first second label not found
goto ] first second label not found

Delimiter after the first word: , : ; = + . / [ \ ]
goto first,second jumps to :first
goto first:second jumps to :first
goto first;second jumps to :first
goto first=second jumps to :first
goto first+second jumps to :first
goto first.second jumps to :first
goto first[second jumps to :first
goto first\second jumps to :first
goto first]second jumps to :first
goto first/second jumps to :first

Delimiter combinations
goto+first+second third jumps to :third
goto.first.second third jumps to :third
goto[first[second third jumps to :third
goto\first\second third jumps to :third
goto]first]second third jumps to :third

Special effect with : :
goto x:second jumps to :second if x has only one character.
Therefore goto driveC:\WINDOWS\TEMP jumps to :driveC
But goto C:\WINDOWS\TEMP goes to nowhere because :\ isn't a guilty label.
Example:
::DRIVE.BAT extracts the drive letter from the path
goto _%1
:_A
set drive=A
goto end
:_B
set drive=B
goto end
:_C
set drive=C
goto end
:_D
set drive=D
goto end
::and so on
:_ set drive=
:end

This is faster than a redirection method. GOTO is one of the fastest commands.

Quotes I
goto"first second third label not found
goto" first second third label not found
goto"first:second third jumps to :second
goto"first second :third jumps to :third
goto" first :second third jumps to :second
goto" first second :third jumps to :third

goto""first second jumps to :second
goto" "first second jumps to :second
goto"first " second jumps to :second
goto"first ": second jumps to :second
goto"first second" third jumps to :third

Quotes II
goto "first and goto fir"st jump to :first

goto "first" and goto fir"st" jump to :first
goto "first second" and goto first";"second jump to :first
goto 12345678" ".txt and goto 12345678." "txt jump to :12345678

goto " first" and goto " "first and goto " ":first jump to :first
goto " " first and goto " " :first label not found
goto "" first jumps to :first
goto "" "" first and goto "" "" :first label not found

Uppercase and Lowercase

GOTO is not case sensitive:
goto Ab jumps to :aB
goto `{}~ jumps to :@[]^_
because GOTO treats `{}~ as lowercase of @[]^_
(Note that goto {} jumps to :[] but goto [] label not found)

goto label- jumps to the second line below :label
because the GOTO command treats binary 13 (end of line) as uppercase of binary 45 (-).
(Thererfore it doesn't work with :label, or :label; etc.)
goto 12345678.- jumps to the second line below :12345678
goto 12345678.90- jumps to the second line below :1234567890
Example:
if %name%_==_ goto label-
if not %name%_==_ goto label
:label
for %%T in (echo goto:end) do %%T this is the first line
for %%T in (echo goto:end) do %%T this is the second line
:end

This trick uses one label instead of two.


IF

delimiter , ; whitespace Tab =
if "==" echo true
if,E==E;echo true
if=/==/=echo true

If the first expression contains a delimiter, IF compares the first part of the first expression with the second expression:
if A B==A echo true
if A B C==;A echo true
Example: Get the first word of a sentence:
set variable=some words
for %%T in (%variable%) do if %variable%==%%T set variable=%%T

The second expression must contain one word only:
if "A B"=="A B" echo true command or filename not found

if "==" echo "<" is possible but if not A==" echo "<" doesn't work.
Echoing "<", ">", "|" is difficult if only one of the two expressions contains a quote.
if not "==A echo" "<" also doesn't work.
Even if not A==" if not A==" echo "<" doesn't help.

"=" in the middle of the first expression is not allowed:
if A=B==A echo true Syntax Error
if A"="B ==A echo true Syntax Error
But
if =A==A echo true works,
if A===A echo true works,
if =A===A echo true works,
if ==A====A echo true works.


IF EXIST

IF EXIST finds both short and long filenames.
Therefore the file 1234576890.12345
is found by
if exist 1234567890.1* echo true as well as by
if exist 123456~1.123* echo true
also by
if exist 123456?????1* echo true as well as by
if exist 123456?????3* echo true
and by
if exist 123456?8* echo true as well as by
if exist 123456?1* echo true

if exist * echo true looks for all files.
if exist *.* echo true looks for all files, too.
if exist *.*.* echo true looks for files of the form a.b.c, a.b.c.d and so on.
if exist *.*.*.* echo true looks for files of the form a.b.c.d, a.b.c.d.e and so on.

if exist *.?* echo true looks for files with extension.

if exist *. echo true looks for files without extension.
if exist *.*. and if exist *.*.*. and if exist *.*.*.*. find nothing.
Read also the chapter FOR.

if exist ???? echo true   looks for filenames with 3-4 characters.
How to look for filenames with exact 4 characters? - I don't know.