How to expand a CMD shell variable twice (recursively)

后端 未结 7 994
温柔的废话
温柔的废话 2020-12-01 13:03

Using the Windows XP CMD command-line I can expand a variable twice as follows:

set AAA=BBB
set BBB=CCC
for /F \"usebackq tokens=*\" %i in (`echo %%AAA%%`) d         


        
相关标签:
7条回答
  • 2020-12-01 13:31

    How to expand a shell variable multiple times:

    @echo off
    setlocal enabledelayedexpansion
    
    set myvar=second
    set second=third
    set third=fourth
    set fourth=fifth
    
    echo Variable value before expansion: !myvar!
    call :expand myvar
    echo Variable value after expansion: !myvar!
    goto :eof
    
    
    :expand
        set var=%1
        :expand_loop
            if not "!%var%!" == "" (
                set var=!%var%!
                goto :expand_loop
            )
            set %1=!var!
        goto :eof
    

    output:

    Variable value before expansion: second
    Variable value after expansion: fifth
    
    0 讨论(0)
  • 2020-12-01 13:31

    This aaa.bat

    @echo off
    set aaa=bbb
    set bbb=ccc
    for /F %%i in ('echo %%%aaa%%%') do echo %%i
    

    outputs

    c:>ccc
    

    What exactly is the trouble?

    0 讨论(0)
  • 2020-12-01 13:32

    The following (torturous) approach seems to work okay:

        @echo off
    :main
        setlocal enableextensions enabledelayedexpansion
        set aaa=bbb
        set bbb=ccc
        call :myset x %%aaa%%
        echo %x%
        endlocal
        goto :eof
    :myset
        for /F "usebackq tokens=*" %%i in (`echo %%%2%%`) do set %1=%%i
        goto :eof
    

    It outputs:

    ccc
    

    as desired.

    I've often used that trick to (for example) format %aaa% into %x% to a certain size (a la sprintf) but this is the first time I've had to do double indirection. It works because you don't find the extra "%%" being sucked up by the current shell level.

    0 讨论(0)
  • 2020-12-01 13:33

    it seems like the easiest thing to do is to create a tiny temp file to set the variable as you wish. something like this should work:

    setlocal enabledelayedexpansion
    
    set LIST=BBB CCC DDD
    set BBB=111
    set CCC=222
    set DDD=333
    
    for %%i in (%LIST%) do (
        echo set a=\%%%i\%>tmp.bat
        call tmp.bat
        echo %a
        rm tmp.bat
    )
    
    0 讨论(0)
  • 2020-12-01 13:35

    The OP question almost works on Windows 10. A small correction is required to properly form the ECHO command. Here is the intermediate result:

    set LIST=BBB CCC DDD
    set BBB=111
    set CCC=222
    set DDD=333
    for %%i in (%LIST%) do echo %%%%i%%
    
    rem // Outputs:
    rem // %AAA%
    rem // %BBB%
    rem // %CCC%
    

    Then we nest the output inside another FOR statement and get the completed result:

    set LIST=BBB CCC DDD
    set BBB=111
    set CCC=222
    set DDD=333
    for %%i in (%LIST%) do for /f %%a in ('echo %%%%i%%') do echo %%a
    
    rem // Outputs:
    rem // 111
    rem // 222
    rem // 333
    
    0 讨论(0)
  • 2020-12-01 13:50

    Thinking in terms of a less tortuous solution, this, too, produces the CCC you desire.

    setlocal enabledelayedexpansion
    set AAA=BBB
    set BBB=CCC
    for /F  %%a in ('echo %AAA%') do  echo !%%a!
    

    edit:

    to dissect this answer:

    setlocal enabledelayedexpansion - this will allow for any environment variable setting during your bat to be used as modified during the process of your for loop.

    set AAA=BBB, set BBB=CCC - your data population set statements

    for /F %%a in ('echo %AAA%') do echo !%%a! - This tells the processor to loop, albeit only once, and take out the first token that is returned (default delimiter of space and tab apply) from the running of the command in the parens and put it in the var %%a (outside of a batch, a single % will do). If you specify that var as %%a, you need to use %%a in your do block. Likewise, if you specify %%i, use %%i in your do block. Note that to get your environment variable to be resolved within the do block of the for loop, you need surround it in !'s. (you don't need to in the in block, as I originally posted - I have made that change in my edit).

    edit:

    You were very close with your updated example. Try it like this:

    @echo off
    setlocal enabledelayedexpansion
    set LIST=BBB CCC DDD
    set BBB=111
    set CCC=222
    set DDD=333
    
    for %%i in (%LIST%) do (
        for /F %%a in ('echo %%i') do echo !%%a!
    )
    

    The difference between your update and this is that you were trying to echo the environment variable in the in set with in ('echo %%%i%'), but without the !'s for the delayed expansion of set variables. Were you to use in ('echo !%%i!'), you would see your BBB, CCC, and DDD variables resolved, but then the do block of your inner loop wouldnt have anything to resolve - you dont have any 111 environment variables. With that in mind, you could simplify your loop with the following:

    @echo off
    setlocal enabledelayedexpansion
    set LIST=BBB CCC DDD
    set BBB=111
    set CCC=222
    set DDD=333
    
    for %%i in (%LIST%) do (echo !%%i!)
    
    0 讨论(0)
提交回复
热议问题