I have two .bat
files, both use delayed expansion, so that I can set variables within for loops.
The example below is greatly simplified just to show the problem
Script one.bat
@echo off
setlocal enableextensions
setlocal enabledelayedexpansion
set j=0
for /L %%i in (1,1,2) do (
set j=%%i
set /A j=!j! + 1
echo %%i !j!
two.bat
echo %%i !j!
)
Script two.bat
@echo off
setlocal enableextensions
setlocal enabledelayedexpansion
echo Hello World
exit /B 0
On return from two.bat
variable !j!
is lost and echo
is turned back on.
J:\>one
1 2
Hello World
1 !j!
J:\>(
set j=2
set /A j=!j! + 1
echo 2 !j!
two.bat
echo 2 !j!
)
Missing operator.
2 !j!
Hello World
2 !j!
Yes I could make two.bat
a sub-routine in one.bat
but its hundred of lines long and I dont want to have to maintain two copies of the same logic
What am I missing here ?
Your assumption is wrong that execution returns from file
two.bat
, because that is only the case when you are using thecall
command1.The batch file
one.bat
runstwo.bat
within a parenthesised block of code, which is already in a command stack2, so the block is (kind of) finished before terminating execution.Your output perfectly illustrates what happens (therefore I commented it here):
To prove whether execution happens under batch file or Command Prompt context, just place
set /A j
in the loop body inone.bat
as the last command, so you will get an additional output0
after the output1 !j!
and the second2 !j!
, becauseset /A
does not return anything in batch file context, but it outputs the (last) result (without a trailing line-break) in Command Prompt context; the value of0
shows thatj
is no longer set.1) There are a few exceptions: the called batch file is involved in a pipe, or it is run and parsed by a
for /F
loop, because the batch file runs in a newcmd.exe
instance in such cases.2) The same would be true if the called batch file was involved in a line with concatenated commands, hence something like
two.bat & echo Fine
would echoFine
upon execution oftwo.bat
.