Reputation: 177
When writing scripts in Windows batch files, sometimes the proper execution of the script requires the use of the setlocal
command. My main complaint about using setlocal
is that I'm often performing complicated for & if statements in which I set variable values in that section of code. These settings are lost when I issue the command endlocal
.
So far I've worked around this by echoing the variable value into a scratch file within the setlocal
segment and then read the value back into the variable after the endlocal
. However, it seems like there should be a more elegant solution to the problem.
The suggested answer provides a handy way to circumvent the issue if only using one or multiple set
statements. However, the linked answer does not provide a solution when the setlocal
is in place to allow a for
loop to properly expand variable names at time of execution rather than parsing. In my situation, I also have if
statement logic tree to perform further checking on that information to set
many different possible variable values. The linked solution does not provide a solution to this situation.
This code is supposed to check an install package for its version number. It is called from another script that requires that version number to function correctly. We know the package is named using the form [application][version number].msi. The [version number] can be any of the following:
It is possible that more than one install package exists in the designated directory so it's important to look through them all and select the highest version in the directory.
I inherited and expanded the code to correctly process the 10 & 10.1 versions. If there's a better way to do this without the setlocal (e.g. I've thought of rewriting to use a case statement) I'd love to see a better solution.
However, I'm still interested in learning how to pass variables out of the setlocal
/ endlocal
segment.
setlocal enabledelayedexpansion
for /f %%a in ('dir /b program*.MSI') do (
set FileName=%%a
set tst1=!FileName:~4,3!
if "!tst1!" == "msi" (
rem Only true if it has a 1 digit number (e.g. "9")
set MAIN_VERSION=!FileName:~2,1!
) else (
set tst2=!FileName:~5,3!
if "!tst2!" == "msi" (
rem Only true if it has a 2 digit version number (e.g. "10")
set MAIN_VERSION=!FileName:~2,2!
) else (
... lots more code ...
)
)
)
rem Write results out to a file for temporary storage. This particular
rem form of echo is required to ensure there are no trailing spaces, CR,
rem or LF
echo|set /P ="!MAIN_VERSION!" > %USERPROFILE%\UGV.txt
rem End local variables
endlocal
rem Read the correct version out of our temporary storage file
set /p MAIN_VERSION=<%USERPROFILE%\UGV.txt
How do I pass a variable (such as MAIN_VERSION
above) out of a Windows batch script setlocal
/ endlocal
code segment without using a scratch file?
Upvotes: 6
Views: 2868
Reputation: 82247
To preserve variables over the setlocal/endlocal scope, there exists different solutions.
It depends of the situation which one you should use.
Works only outside of parenthesis blocks with simple content, but can produce problems with special characters like !^"
.
setlocal
set localVar=something simple
...
(
endlocal
set "out=%localVar%"
)
set out
Works also in blocks and can handle the most characters, but can fail with !^
and linefeed/carriage return
if 1==1 (
setlocal EnableDelayedExpansion
set "localVar=something medium nasty & "^&"
for /F "delims=" %%V in ("!localVar!") DO (
endlocal
set "out=%%V"
)
)
set out
Works for all contents in any situation
SO: preserving exclamation marks in variable between setlocals batch
Upvotes: 5