Windows batch setlocal enabledelayedexpansion call return value

后端 未结 1 930
既然无缘
既然无缘 2021-01-17 04:55

There are two (2) Windows batch scripts. The first one will CALL the second one. However, SETLOCAL must be used around the call to the second batch script because ENABLEDELA

相关标签:
1条回答
  • 2021-01-17 05:11

    If you are in a loop, or any parenthesized block of code, then you cannot use the ENDLOCAL & set BAT2_VAR=%BAT2_VAR% method.

    Something like this would fail

    REM delayed expansion is disabled to start
    for ... %%A in (....) do (
       REM must SET before enabling delayed expansion to preserve ! in %%A value
       set var=%%A
       REM the remainder of the loop needs delayed expansion
       setlocal enableDelayedExpansion
       REM do something with !var!
       call batch2 !var!
       REM maybe the batch2 modifies var some more
       REM Must endlocal and preserve the value. The attempt below fails because %var% will
       REM be the value that existed before the loop was entered
       endlocal & set "var=%var%"
    )
    

    A simple fix is to transfer the value via a FOR variable

    REM delayed expansion is disabled to start
    for ... %%A in (....) do (
       REM must SET before enabling delayed expansion to preserve ! in %%A value
       set var=%%A
       REM the remainder of the loop needs delayed expansion
       setlocal enableDelayedExpansion
       REM do something with !var!
       call batch2 !var!
       REM maybe the batch2 modifies var some more
       REM the code below successfully transports the value across the endlocal barrier
       for /f "delims=" %%B in ("!var!") do endlocal & set "var=%%B"
    )
    

    You say your batch might set many values you need to preserve. Normally you pass the names of the return variables into your CALLed routine, and then your routine could do something like:

    set "%~2=return value1"
    set "%~3=return value2"
    ... etc.
    

    You would know the names of all the variables, but that might require a lot of code to transport all values accross the endlocal barrier.

    You could prefix all the variables with a common prefix, and then use a FOR /F loop to preserve the values. The entire result set of a FOR /F ('command') is cached before any of the iterations begin.

    Your CALLed batch could set variables prefix.var1, prefix.var2, ... prefix.varN, and the following code would work

    REM delayed expansion is disabled to start
    for ... %%A in (....) do (
       REM must SET before enabling delayed expansion to preserve ! in %%A value
       set var=%%A
       REM the remainder of the loop needs delayed expansion
       setlocal enableDelayedExpansion
       REM do something with !var!
       call batch2 !var! prefix.
       REM the batch2 set variables prefixed by prefix.
       REM Must endlocal and preserve all values.
       for /f "delims=" %%B in ('set prefix.') do (
         if "!"=="" endlocal
         set "%%B"
       )
    )
    

    The if "!"=="" endlocal line is a nifty trick to only endlocal on the 1st inner loop iteration. It relies on the fact that delayed expansion was disabled before the outer loop, and enabled near the top of each outer loop iteration.

    0 讨论(0)
提交回复
热议问题