来自输入的批量变量未更新

时间:2016-01-14 14:25:28

标签: batch-file

我有以下代码段(省略了一些代码):

REM Verify destination_folders.
FOR %%f in (%destination_folders%) do (
    IF NOT EXIST %%f (
        echo(
        echo Destination folder %%f does not exist. Is version %version% correct? Please update the script with your required parameters.
        SET /p continue="Do you want to abort the operation? [Y/N]:"
        echo cont=%continue%

        IF %continue:~0,1%==y (
            goto :eof
        )

        IF %continue:~0,1%==Y (
            goto :eof
        )
    )
)

问题是在脚本执行完之后才会分配变量continue。例如,如果前一次执行continueN,然后输入Y则不会更新它,因此赋值后的回显将输出cont=N尽管它应该是cont=Y。我做错了什么?

1 个答案:

答案 0 :(得分:2)

You need delayed expansion. setlocal enabledelayedexpansion somewhere, and use !continue! instead of %continue%. The problem is that %continue% is expanded as the entire parenthetical code block is read for the first time, so it's treated as flat text by the time for performs its first loop. !continue! retains its variability, and it's re-evaluated on each iteration.

You can also avoid the delayed expansion problem by using choice and if errorlevel like this:

REM Verify destination_folders.
FOR %%f in (%destination_folders%) do (
    IF NOT EXIST "%%~f" (
        echo(
        echo Destination folder %%f does not exist. Is version %version% correct?
        echo Please update the script with your required parameters.

        choice /N /M "Do you want to abort the operation? [Y/N]: "
        if not errorlevel 2 goto :EOF
    )
)

To learn in greater detail about delayed expansion, read this portion of the help set documentation:

Finally, support for delayed environment variable expansion has been added. This support is always disabled by default, but may be enabled/disabled via the /V command line switch to CMD.EXE. See CMD /?

Delayed environment variable expansion is useful for getting around the limitations of the current expansion which happens when a line of text is read, not when it is executed. The following example demonstrates the problem with immediate variable expansion:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "%VAR%" == "after" @echo If you see this, it worked
)

would never display the message, since the %VAR% in BOTH IF statements is substituted when the first IF statement is read, since it logically includes the body of the IF, which is a compound statement. So the IF inside the compound statement is really comparing "before" with "after" which will never be equal. Similarly, the following example will not work as expected:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%

in that it will NOT build up a list of files in the current directory, but instead will just set the LIST variable to the last file found. Again, this is because the %LIST% is expanded just once when the FOR statement is read, and at that time the LIST variable is empty. So the actual FOR loop we are executing is:

for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different character (the exclamation mark) to expand environment variables at execution time. If delayed variable expansion is enabled, the above examples could be written as follows to work as intended:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "!VAR!" == "after" @echo If you see this, it worked
)

set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%