ENDLOCAL & SET VAR=%TEMPVAR%
模式很經典。但有些情況並不理想。
如果你不知道的TempVar的內容,那麼你可能會如果值包含特殊字符,如<
>
&
或|
遇到的問題。通常可以使用SET "VAR=%TEMPVAR%"
等引號來防止這種情況發生,但如果存在特殊字符並且該值已經被引用,則會導致問題。
如果您擔心特殊字符,FOR表達式是跨越ENDLOCAL屏障傳輸值的絕佳選擇。延遲擴展應在ENDLOCAL之前啓用,並在ENDLOCAL之後禁用。
setlocal enableDelayedExpansion
set "TEMPVAR=This & "that ^& the other thing"
for /f "delims=" %%A in (""!TEMPVAR!"") do endlocal & set "VAR=%%~A"
限制:
如果必須返回多個值,你知道,不能出現在任何一個值,然後只需使用FOR/F選項中選擇合適的字符。例如,如果我知道的值不能包含|
:
setlocal enableDelayedExpansion
set "temp1=val1"
set "temp2=val2"
for /f "tokens=1,2 delims=|" %%A in (""!temp1!"|"!temp2!"") do (
endLocal
set "var1=%%~A"
set "var2=%%~B"
)
如果必須返回多個值,字符集是不受限制的,然後使用嵌套FOR/F循環:
setlocal enableDelayedExpansion
set "temp1=val1"
set "temp2=val2"
for /f "delims=" %%A in (""!temp1!"") do (
for /f "delims=" %%B in (""!temp2!"") do (
endlocal
set "var1=%%~A"
set "var2=%%~B"
)
)
肯定請查閱jeb's answer,以獲取適用於所有情況下所有可能值的安全防彈技術。
2017年8月21日 - 新功能RETURN.BAT
我已經與DosTips用戶傑布合作開發a batch utility called RETURN.BAT可以從腳本中使用退出或調用的程序,並返回一個或多個變量跨越ENDLOCAL的障礙。非常酷:-)
以下是版本3.0的代碼。我很可能不會保持此代碼是最新的。最好按照鏈接確保您獲得最新版本,並查看一些示例用法。
RETURN.BAT
::RETURN.BAT Version 3.0
@if "%~2" equ "" (goto :return.special) else goto :return
:::
:::call RETURN ValueVar ReturnVar [ErrorCode]
::: Used by batch functions to EXIT /B and safely return any value across the
::: ENDLOCAL barrier.
::: ValueVar = The name of the local variable containing the return value.
::: ReturnVar = The name of the variable to receive the return value.
::: ErrorCode = The returned ERRORLEVEL, defaults to 0 if not specified.
:::
:::call RETURN "ValueVar1 ValueVar2 ..." "ReturnVar1 ReturnVar2 ..." [ErrorCode]
::: Same as before, except the first and second arugments are quoted and space
::: delimited lists of variable names.
:::
::: Note that the total length of all assignments (variable names and values)
::: must be less then 3.8k bytes. No checks are performed to verify that all
::: assignments fit within the limit. Variable names must not contain space,
::: tab, comma, semicolon, caret, asterisk, question mark, or exclamation point.
:::
:::call RETURN init
::: Defines return.LF and return.CR variables. Not required, but should be
::: called once at the top of your script to improve performance of RETURN.
:::
:::return /?
::: Displays this help
:::
:::return /V
::: Displays the version of RETURN.BAT
:::
:::
:::RETURN.BAT was written by Dave Benham and DosTips user jeb, and was originally
:::posted within the folloing DosTips thread:
::: http://www.dostips.com/forum/viewtopic.php?f=3&t=6496
:::
::==============================================================================
:: If the code below is copied within a script, then the :return.special code
:: can be removed, and your script can use the following calls:
::
:: call :return ValueVar ReturnVar [ErrorCode]
::
:: call :return.init
::
:return ValueVar ReturnVar [ErrorCode]
:: Safely returns any value(s) across the ENDLOCAL barrier. Default ErrorCode is 0
setlocal enableDelayedExpansion
if not defined return.LF call :return.init
if not defined return.CR call :return.init
set "return.normalCmd="
set "return.delayedCmd="
set "return.vars=%~2"
for %%a in (%~1) do for /f "tokens=1*" %%b in ("!return.vars!") do (
set "return.normal=!%%a!"
if defined return.normal (
set "return.normal=!return.normal:%%=%%3!"
set "return.normal=!return.normal:"=%%4!"
for %%C in ("!return.LF!") do set "return.normal=!return.normal:%%~C=%%~1!"
for %%C in ("!return.CR!") do set "return.normal=!return.normal:%%~C=%%2!"
set "return.delayed=!return.normal:^=^^^^!"
) else set "return.delayed="
if defined return.delayed call :return.setDelayed
set "return.normalCmd=!return.normalCmd!&set "%%b=!return.normal!"^!"
set "return.delayedCmd=!return.delayedCmd!&set "%%b=!return.delayed!"^!"
set "return.vars=%%c"
)
set "err=%~3"
if not defined err set "err=0"
for %%1 in ("!return.LF!") do for /f "tokens=1-3" %%2 in (^"!return.CR! %% "") do (
(goto) 2>nul
(goto) 2>nul
if "^!^" equ "^!" (%return.delayedCmd:~1%) else %return.normalCmd:~1%
if %err% equ 0 (call) else if %err% equ 1 (call) else cmd /c exit %err%
)
:return.setDelayed
set "return.delayed=%return.delayed:!=^^^!%" !
exit /b
:return.special
@if /i "%~1" equ "init" goto return.init
@if "%~1" equ "/?" (
for /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do @echo(%%A
exit /b 0
)
@if /i "%~1" equ "/V" (
for /f "tokens=* delims=:" %%A in ('findstr /rc:"^::RETURN.BAT Version" "%~f0"') do @echo %%A
exit /b 0
)
@>&2 echo ERROR: Invalid call to RETURN.BAT
@exit /b 1
:return.init - Initializes the return.LF and return.CR variables
set ^"return.LF=^
^" The empty line above is critical - DO NOT REMOVE
for /f %%C in ('copy /z "%~f0" nul') do set "return.CR=%%C"
exit /b 0
我喜歡下面的所有答案,顯示如何處理各種邊界情況,不會與您的具體問題發揮作用。 (你的最終結果必須是一個合法的目錄,所以它不可能有'!'或';'或其他元字符)。它表明我們所有人都更關心教學,而不是僅僅通過一個答案快速地放風。而且,我的朋友們,是StackOverflow。 – 2015-07-21 20:42:36
我通過在這裏使用reg.exe和volatile註冊表回答了這個問題:https://stackoverflow.com/questions/26246151/setlocal-enabledelayedexpansion-causes-cd-and-pushd-to-not-persist/45369743#45369743 – mosh 2017-07-28 13:32:17
有趣的是,我懷疑被調用的腳本只需要引用它自己的路徑,即IE,「Activate.bat」需要知道它從哪裏被調用,並且將該變量指定爲「腳本」以用於其內部的未來調用。 – 2017-11-16 15:23:33