Reputation: 139
I'm trying to figure how to return multiple variables, in a rather dynamic fashion where I just maintain a list of variable names and then do the ENDLOCAL
"export" with a loop, but it seems the !%%V!
expansion in the inner FOR loop isn't expanding soon enough or so.
Is there something I'm missing or is there another way to accomplish this?
Example code:
SETLOCAL EnableExtensions EnableDelayedExpansion
[...]
SET "RETURN=FOO BAR"
[...]
SET "RETURN=%RETURN% BAZ"
[...]
:END
:: "Export" %FOO%, %BAR%, and %BAZ% to calling context.
ENDLOCAL & (
FOR %%N IN (%RETURN%) DO (
FOR /f %%V in ("%%N") DO SET %%N=!%%V!
)
)
EXIT /B
Thank you for any help.
Upvotes: 2
Views: 1110
Reputation: 11367
Here is a return routine for preserving variables across scope. Just call the return routine with the variables names as parameters and then call endlocal %return%
.
:return [Variables...]
setlocal enabledelayedexpansion
set "return="
:_return
if "%~1"=="" endlocal & exit /b 1
if not defined %~1 goto __return
set "%~1=!%~1:"=""!"
set "%~1=!%~1:^=^^!"
set "%~1=!%~1:<=^<!"
set "%~1=!%~1:>=^>!"
set "%~1=!%~1:&=^&!"
set "%~1=!%~1:|=^|!"
:__return
set "return=!return!^&set ""%~1=!%~1!"""
if not "%~2"=="" shift & goto _return
setlocal disabledelayedexpansion
set "return=%return:!=^^^^^^^!%"
endlocal & endlocal & set "return=%return:""="%"
exit /b 0
call :return foo bar baz
endlocal %return%
Only variable a
will be preserved outside the scope.
@echo off
setlocal
echo Inside
set "a=1"
set "b=2"
echo(%a%
echo(%b%
call :return a
endlocal %return%
echo Outside
echo(%a%
echo(%b%
exit /b 0
:return [Variables...]
setlocal enabledelayedexpansion
set "return="
:_return
if "%~1"=="" endlocal & exit /b 1
if not defined %~1 goto __return
set "%~1=!%~1:"=""!"
set "%~1=!%~1:^=^^!"
set "%~1=!%~1:<=^<!"
set "%~1=!%~1:>=^>!"
set "%~1=!%~1:&=^&!"
set "%~1=!%~1:|=^|!"
:__return
set "return=!return!^&set ""%~1=!%~1!"""
if not "%~2"=="" shift & goto _return
setlocal disabledelayedexpansion
set "return=%return:!=^^^^^^^!%"
endlocal & endlocal & set "return=%return:""="%"
exit /b 0
As for why your code is not working as you expect, is because the variable must be expanded before the endlocal command is run. Read this excellent SO post about host the command line parses batch scripts: Answer: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
|
&
<
>
"
^
!
Upvotes: 2
Reputation: 79983
How about
@ECHO OFF
SETLOCAL
FOR %%i IN (foo bar baz) DO SET $%%i=value:%%i
ECHO == initial values ===
SET $
SET "RETURN=$FOO $BAR"
CALL :demo
ECHO == after CALL modifying %return% ===
SET $
FOR %%i IN (foo bar baz) DO SET $%%i=value:%%i
ECHO == initial values ===
SET $
SET "RETURN=%RETURN% $BAZ"
CALL :demo
ECHO == after CALL modifying %return% ===
SET $
GOTO :eof
:demo
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%i IN (foo bar baz) DO SET $%%i=modified:%%i
SET "$retvals="
FOR %%N IN (%RETURN%) DO SET "$retvals=!$retvals!^&set %%N=%%%%N%%"
CALL SET "$retvals=%$retvals%"
:: "Export" %FOO%, %BAR%, and %BAZ% to calling context.
endlocal%$retvals%
EXIT /B
GOTO :EOF
Yielding
== initial values ===
$bar=value:bar
$baz=value:baz
$foo=value:foo
== after CALL modifying $FOO $BAR ===
$bar=modified:bar
$baz=value:baz
$foo=modified:foo
== initial values ===
$bar=value:bar
$baz=value:baz
$foo=value:foo
== after CALL modifying $FOO $BAR $BAZ ===
$bar=modified:bar
$baz=modified:baz
$foo=modified:foo
(I just changed the varnames for convenience of display using set
)
Upvotes: 0
Reputation: 67216
:: "Export" %FOO%, %BAR%, and %BAZ% to calling context.
for %%a in ("endlocal" "FOO=%FOO%" "BAR=%BAR%" "BAZ=%BAZ%") do (
if %%a equ "endlocal" (endlocal) else set %%a
)
exit /B
Upvotes: 1