Recursion in Batch Files
There are five main approaches to recursion, some with variants:
vector absolute on non-null argument
@echo off
if not "%1" == "" goto pass2
and it's variant
vector absolute on null argument
@echo off
if "%1" == "" goto pass2
vector to argument on non-null argument
@echo off
if not "%1" == "" goto %1
vector absolute on flag
@echo off
if "%1" == "}{" goto pass2
vector to argument on flag
@echo off
if "%1" == "}{" goto %2
and the variant in which the GOTO command is also an argument
@echo off
if "%1" == "}{" %2 %3
where %2 contains the command and %3 the target - this is more abstract, and lead me to the third approach:
vector or not, with the entire command being variable
@echo off
%1 %2
or
@echo off
%fork%
Note that in the last two cases, not even the existence, let alone the nature of the command is determined when the program begins. This approach is totally virtual - the command can be nothing at all, as would usually, but not always, be the case on the first pass; it can be something other than a recursion vector - for example, a command to call another batch file or executable; or it can be a vector to code within the program, determined from outside on the first pass and from its own code on subsequent passes. It may not look like it, but this is deep magic. More on this later, after examining the simpler cases.
The vector absolute on null or non-null argument are the simplest and least useful - there can be only one possible target, which limits the recursion to just two levels. However, there is the possibility of combining the non-null case with one or another of the other cases to make compound recursion vectoring in which the presence of any argument directs the program flow to a place in the code where more detailed analysis of the arguments takes place:
@echo off
if not "%1" == "" goto vector
... initialization code goes here
... something call %0 }{ foo
... or
... something call %0 foo
goto end
:vector
if %1 == }{ goto %2
REM else
goto %1
... various code blocks and labels go here
:end
I see no
advantage in this over the totally variable construct.
Note: the use of "}{" as a marker is something I introduced to the MSDOS forum
on Compuserve a couple of years before I introduced the totally variable
syntax, and has no significance beyond its rarity - which makes it extremely
unlikely that the marker would duplicate a real argument needed by any batch
file. If you have a case in which it does, just change the marker - the only
requirement is that it not duplicate any valid real argument.
The various flagged vector constructs are the safest ways to handle vectoring during recursion. There is little to chose among them, except that the ones using a variable target argument are more versatile in that they allow deeper recursion.
I said above that the virtual command approach is deep magic - it is also somewhat limited in that it cannot be used in batch files that require real arguments. Where it can be used, it allows not only recursion, but also determination of at least a couple of command lines in a batch file at execution time:
@echo off
%1 %2
%3 %4
:end
is a trivial example - the batch file consists of any one or two two word commands, but which ones they are isn't determined until the program is run. If run with no arguments, it does nothing. If invoked (assuming it is named FOO.BAT)
foo dir *.* del *.bat
it would perform
a
DIR *.*
on the current directory and then delete all the batch files, including
itself, from the default directory. This isn't really useful, but it
illustrates the concept that the same syntax that is used to control recursion
vectoring can also be used for other purposes - even in the same batch file:
@echo off
%1 %2 %3
if exist %0.txt call $0 goto pass2
:goto end
:pass2
dir %0.*
:end
Assuming that the program is named FOO.BAT and that FOO.TXT does not exist, if it is invoked with the arguments
foo copy foo.bat foo.txt
its behavior would be rather different from when it was invoked with no arguments, and the exact same syntax (%1 %2 %3) would have had actions of totally different natures on the two passes (first case only), and would never act as vectoring code at all in the second case. This virtual command concept is so new that I really haven't had time to explore its implications.