How to modify environment variable value inside a loop?

后端 未结 1 1111
臣服心动
臣服心动 2021-01-29 02:58

I have following code in a batch file:

set \"start=2\"

FOR /L %%a in (1,1,3) DO (
    FOR /L %%b in (%start%,1,3) DO (
        echo %start% Before Call
                 


        
1条回答
  •  -上瘾入骨i
    2021-01-29 03:41

    Following is output up to first execution of pause on running the batch file as posted in question from within a command prompt window without @echo off as usually used at top of a batch file to debug this batch file:

    set "start=2"
    
    FOR /L %a in (1 1 3) DO (FOR /L %b in (2 1 3) DO (
    echo 2 Before Call
     call :changestring
     FOR /L %c in (1 1 3) DO (REM Nothing )
    ) )
    
    (FOR /L %b in (2 1 3) DO (
    echo 2 Before Call
     call :changestring
     FOR /L %c in (1 1 3) DO (REM Nothing )
    ) )
    
    (
    echo 2 Before Call
     call :changestring
     FOR /L %c in (1 1 3) DO (REM Nothing )
    )
    2 Before Call
    
    echo 2 Before Set
    2 Before Set
    
    set "start=1"
    
    echo 1 After Set
    1 After Set
    
    pause
    

    Windows command interpreted cmd.exe interpreting the batch file and executing the command lines outputs with no echo off always the command line before execution after preprocessing/parsing it as described at How does the Windows Command Interpreter (CMD.EXE) parse scripts?

    It can be seen that the command block starting with ( and ending with matching ) is completely preprocessed by Windows command interpreter before executing the most outer FOR command the first time. Both occurrences of %start% have been replaced during preprocessing the entire command block by the current value 2 of referenced environment variable. So the entire command block used next several times by FOR does not contain anymore an environment variable reference. Only the loop variable references remain in command block.

    The help of command SET output on running set /? in a command prompt window describes this problematic of all environment variable references done with %variable% being evaluated already during preprocessing. And help of SET describes also what is the solution for an IF condition and a FOR loop on which current value of environment variable changes within the command block or during loop execution: the usage of delayed expansion.

    So let's use the commands SETLOCAL and ENDLOCAL as explained in this answer to enable also delayed environment variable expansion in addition to command extensions which are enabled by default and needed here too.

    setlocal EnableExtensions EnableDelayedExpansion
    set "start=2"
    
    FOR /L %%a in (1,1,3) DO (
        FOR /L %%b in (!start!,1,3) DO (
            echo !start! Before Call
            call :changestring
            FOR /L %%c in (1,1,3) DO (
                REM Nothing
            )
        )
    )
    
    endlocal
    pause
    goto :EOF
    
    :changestring
    echo %start% Before Set
    set "start=1"
    echo %start% After Set
    pause
    goto :EOF
    

    The environment variable start is referenced now twice with !start! in second FOR command line and its command block which means with delayed expansion as being enabled in first line of modified batch file.

    The output by Windows command interpreter up to first pause on running this modified batch file is now:

    setlocal EnableExtensions EnableDelayedExpansion
    
    set "start=2"
    
    FOR /L %a in (1 1 3) DO (FOR /L %b in (!start! 1 3) DO (
    echo !start! Before Call
     call :changestring
     FOR /L %c in (1 1 3) DO (REM Nothing )
    ) )
    
    (FOR /L %b in (!start! 1 3) DO (
    echo !start! Before Call
     call :changestring
     FOR /L %c in (1 1 3) DO (REM Nothing )
    ) )
    
    (
    echo !start! Before Call
     call :changestring
     FOR /L %c in (1 1 3) DO (REM Nothing )
    )
    2 Before Call
    
    echo 2 Before Set
    2 Before Set
    
    set "start=1"
    
    echo 1 After Set
    1 After Set
    
    pause
    

    Both !start! remain in command block unmodified after preprocessing. So it really references now always the current value of environment variable start being modified during execution of the loops.

    There is no need to replace %start% in the subroutine by !start! as it can be seen because both echo command lines are not within a command block and so each command line is preprocessed with replacing %start% by current value of environment variable just before immediately executing the command ECHO.

    I hope the difference between immediate and delayed expansion of environment variables during preprocessing/parsing a single command line or an entire command block is clear now.

    By the way: The name start for the variable is not good. start can be used as environment variable name, but there is also the command START which could be used in same batch file making it more difficult to distinguish between environment variable start and command start. Better would be as variable name for example FirstNumber.

    An optimized code on which FirstNumber is used instead of start and on which the number is decremented using an arithmetic expression making it possible to reference an environment variable without usage of % or ! and nevertheless using current value of environment variable during evaluation of the arithmetic expression. The first number starting with 2 should be never decremented to a value lower than 1 being the reason for binary OR it with 1.

    @echo off
    setlocal EnableExtensions EnableDelayedExpansion
    set "FirstNumber=2"
    
    FOR /L %%a in (1,1,3) DO (
        FOR /L %%b in (!FirstNumber!,1,3) DO (
            echo !FirstNumber! before decrement
            set /A "FirstNumber=FirstNumber - 1 | 1"
            FOR /L %%c in (1,1,3) DO REM Nothing
        )
    )
    
    endlocal
    

    The output on running this batch file with @echo off at top is:

    2 before decrement
    1 before decrement
    1 before decrement
    1 before decrement
    1 before decrement
    1 before decrement
    1 before decrement
    1 before decrement
    

    Of course set /A "FirstNumber=FirstNumber - 1 | 1" could be here simply a standard string to environment variable assignment, i.e. set "FirstNumber=1". But I wanted to demonstrated that environment variables can be referenced by just their names within an arithmetic expression to make use of current values of the environment variables during evaluation of the expression. This behavior is also described by help of command SET.

    For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

    • call /?
    • echo /?
    • endlocal /?
    • for /?
    • goto /?
    • pause /?
    • rem /?
    • set /?
    • setlocal /?

    Conclusion: Reading carefully the help or documentation of a command, application, or function to use is always good practice for a programmer or script writer to avoid problems on writing coding.

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