Code: Select all
@echo off
setlocal disableDelayedExpansion
echo.
echo * %~n0 { %1 }
set /a rearg1 = %1 - 1
if %rearg1% leq 0 goto :done
echo * before call :exec %0 %rearg1%
call :exec-fail %%0 rearg1
echo ..after call :exec %0 %rearg1%
:done
echo ..%~n0 %1 done
endlocal
goto :eof
:exec
call echo * begin :exec %%1 %%%~2%%
setlocal enableDelayedExpansion
set "exec=%1 !%~2!"
echo * before !exec!
!exec!
echo ..after %1 !%~2!
endlocal
echo * end :exec %1 !%~2!
goto :eof
:exec-fail
call echo * begin :exec2 %%1 %%%~2%%
setlocal enableDelayedExpansion
echo * before %1 !%~2!
%1 !%~2!
echo ..after %1 !%~2!
endlocal
echo * end :exec2 %1 !%~2!
goto :eof
Save it as, say, recurse.cmd, and run it with an argument of 2. Output comes out as expected, copied below.
Code: Select all
C:\>recurse 2
* recurse { 2 }
* before call :exec recurse 1
* begin :exec recurse 1
* before recurse 1
* recurse { 1 }
..recurse 1 done
..after call :exec recurse 1
..recurse 2 done
Now, replace the "call :exec %%0 rearg1" line towards the top with "call :exec-fail %%0 rearg1" and run again...
Code: Select all
C:\>recurse 2
* recurse { 2 }
* before call :exec recurse 1
* begin :exec2 recurse 1
* before recurse 1
* begin :exec2 !rearg1! %
* before 1
'1' is not recognized as an internal or external command,
operable program or batch file.
..after 1
* end :exec2 1
..after call :exec recurse 1
..recurse 2 done
I cannot explain the execution flow between these two lines.
Code: Select all
* before recurse 1
* begin :exec2 !rearg1! %
The only difference between :exec (which works) and :exec-fail (which goes wild) is that the former makes a temporary variable !exec! which it then executes, while the latter attempts to run the same command line directly.
Liviu