Weird scope issue in .bat file

前端 未结 3 1692
小鲜肉
小鲜肉 2020-12-16 12:27

I\'m writing a simple .bat file and I\'ve run into some weird behavior. There are a couple places where I have to do a simple if/else, but the code inside the blocks don\'t

相关标签:
3条回答
  • 2020-12-16 13:11

    You are running into the problem of cmd's static variable expansion. The MODE variable is only evaluated once. You can see this if you omit the @echo off line.

    From the 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%
    
    0 讨论(0)
  • 2020-12-16 13:21

    setlocal EnableDelayedExpansion

    will enable the /v flag

    0 讨论(0)
  • 2020-12-16 13:29

    Looks like the read and write use different scoping rules.

    If you eliminate this line

    set MODE=FOOBAR
    

    it will work as expected. So you'll probably need to have a complex series if if/elses to get the variables populated as you'd like.

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