I am trying to use setlocal/endlocal to use some environment variables internally in a script, but then I do want the script to ultimately save some environment variables as output (i.e., that do take effect in the calling environment).
I thought I could simply have a setlocal
at the beginning, and then wrap any set
commands I want to do outside the script with an endlocal
before and setlocal
after. But it seems to have different behavior if done inside a subroutine vs. outside.
This script should have %var1% == test1
in the calling environment, but not have %var2% == test2
.
@echo off
:main
setlocal
call :set_var1
set var2=test2
exit /b
:set_var1
endlocal
set var1=test1
setlocal
exit /b
However, when I run this, I see:
D:\>set var1=
D:\>echo %var1%
%var1%
D:\>set var2=
D:\>echo %var2%
%var2%
D:\>test.bat
D:\>echo %var1%
%var1%
D:\>echo %var2%
%var2%
So the script failed to set %var1%
.
If I "inline" the code (i.e. cut and paste the code inside the subroutine in the same spot as the subroutine call, and delete the subroutine call), so the script should do the same thing, then it works:
@echo off
:main
setlocal
endlocal
set var1=test1
setlocal
set var2=test2
exit /b
The output looks like:
D:\>set var1=
D:\>echo %var1%
%var1%
D:\>set var2=
D:\>echo %var2%
%var2%
D:\>test.bat
D:\>echo %var1%
test1
D:\>echo %var2%
%var2%
So now %var1%
was correctly set to test1
by the script.
I'm wondering if the exit /b
that returns from a subroutine has some effect on setlocal/endlocal. I don't see anything in the /? usage about this.
How do you selectively have a few environment variables created, or modified, in the batch script, take effect in the calling environment, but in general have most of the variables used for intermediate steps, discarded (i.e., treat them as local to the script)?