I frequently find myself using setlocal
within cmd.exe
to avoid polluting the environment variable space with temporary variables (and to ensure both command extensions and delayed expansion are active).
However, I'm at a loss on how to do this if I actually want one of those variables to be made available.
Consider the following code which gives you the final component of the current directory (so c:\pax\dir1
would give you dir1
):
@echo off :main setlocal enableextensions enabledelayedexpansion call :func echo.main_folder = %folder% endlocal goto :eof :func setlocal enableextensions enabledelayedexpansion set temp=%cd% set folder= :funcloop1 if not "x%temp:~-1%"=="x\" ( set folder=!temp:~-1!!folder! set temp=!temp:~1,-1! goto :funcloop1 ) echo.func_folder = %folder% endlocal goto :eof
When I run this, I get the output:
func_folder = dir1
main_folder =
and you can see that the %folder%
variable does not survive the endlocal
. However, if I leave off the setlocal/endlocal
from the function, the temp
varaible pollutes the namespace of main
.
I know I can just use set temp=
at the end of func
and this will remove the environment variable but that doesn't cover the case where I'm already using that variable in the outside scope (it gets totally destroyed in that case).
Is there a way in cmd.exe
to allow a select group of environment variables to propogate to the outside scope while still preventing others from affecting it? In other words, can you have both local variables and return variables?
Aside, please don't tell me there's a better way of getting the final path component. That is an example case only.
Actually, you can tell me a better way since it'd be nice to know but it won't be answering my specific question :-)
"The solution to this is to take advantage of the fact that the CMD shell evaluates variables on a line-by-line basis - so placing ENDLOCAL on the same line as the SET statement(s) gives the result we want:" source: ss64.com
So changing the endlocal of func: to this...
endlocal & set folder=%folder%
...will get you the behaviour you want.
For better reading and formatting, you can use parentheses.
call :func resultVar
echo(%resultVar%
goto :eof
:func
setlocal
set var=2
(
endlocal
if "%1" NEQ "" set "%1=%var%"
goto :eof
)
This works, because a command block will be expanded like a single line. The parser expands the first two phases (percent variables and escape characters) before executing the command block. The other phases are executed in time (Like delayed expansion, second expand phase by CALL, ...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With