There are two (2) Windows batch scripts. The first one will CALL the second one. However, SETLOCAL must be used around the call to the second batch script because ENABLEDELA
If you are in a loop, or any parenthesized block of code, then you cannot use the ENDLOCAL & set BAT2_VAR=%BAT2_VAR%
method.
Something like this would fail
REM delayed expansion is disabled to start
for ... %%A in (....) do (
REM must SET before enabling delayed expansion to preserve ! in %%A value
set var=%%A
REM the remainder of the loop needs delayed expansion
setlocal enableDelayedExpansion
REM do something with !var!
call batch2 !var!
REM maybe the batch2 modifies var some more
REM Must endlocal and preserve the value. The attempt below fails because %var% will
REM be the value that existed before the loop was entered
endlocal & set "var=%var%"
)
A simple fix is to transfer the value via a FOR variable
REM delayed expansion is disabled to start
for ... %%A in (....) do (
REM must SET before enabling delayed expansion to preserve ! in %%A value
set var=%%A
REM the remainder of the loop needs delayed expansion
setlocal enableDelayedExpansion
REM do something with !var!
call batch2 !var!
REM maybe the batch2 modifies var some more
REM the code below successfully transports the value across the endlocal barrier
for /f "delims=" %%B in ("!var!") do endlocal & set "var=%%B"
)
You say your batch might set many values you need to preserve. Normally you pass the names of the return variables into your CALLed routine, and then your routine could do something like:
set "%~2=return value1"
set "%~3=return value2"
... etc.
You would know the names of all the variables, but that might require a lot of code to transport all values accross the endlocal barrier.
You could prefix all the variables with a common prefix, and then use a FOR /F loop to preserve the values. The entire result set of a FOR /F ('command') is cached before any of the iterations begin.
Your CALLed batch could set variables prefix.var1
, prefix.var2
, ... prefix.varN
, and the following code would work
REM delayed expansion is disabled to start
for ... %%A in (....) do (
REM must SET before enabling delayed expansion to preserve ! in %%A value
set var=%%A
REM the remainder of the loop needs delayed expansion
setlocal enableDelayedExpansion
REM do something with !var!
call batch2 !var! prefix.
REM the batch2 set variables prefixed by prefix.
REM Must endlocal and preserve all values.
for /f "delims=" %%B in ('set prefix.') do (
if "!"=="" endlocal
set "%%B"
)
)
The if "!"=="" endlocal
line is a nifty trick to only endlocal on the 1st inner loop iteration. It relies on the fact that delayed expansion was disabled before the outer loop, and enabled near the top of each outer loop iteration.