windows 如何将 CMD shell 变量扩展两次(递归)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1199931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 12:53:46  来源:igfitidea点击:

How to expand a CMD shell variable twice (recursively)

windowsshellscriptingbatch-filecmd

提问by jon-hanson

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

使用 Windows XP CMD 命令行,我可以将变量扩展两次,如下所示:

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

will echo CCC. I.e. AAAhas been expanded to the string BBB, and then the variable BBBhas been expanded to CCC.

会回声CCC。即AAA已经扩大到字符串BBB,然后变量BBB已经扩大到CCC

This doesn't work from inside a batch script (i.e. a .cmd file). Changing the %%AAA%%to either %%%AAA%%%or %%%%AAA%%%%doesn't work either.

这在批处理脚本(即 .cmd 文件)中不起作用。将 更改%%AAA%%%%%AAA%%%%%%%AAA%%%%也不起作用。

Any idea how i can achieve this from within a script, namely to take expand the variable AAA to the string CCC?

知道如何从脚本中实现这一点,即将变量 AAA 扩展为字符串 CCC?

Late Edit

后期编辑

The answers posted work for my reduced example however the non-tortuous answer doesn't work for the real case. Here's an extended example (which doesn't work), which illustrates what I was actually trying to do:

答案发布适用于我的简化示例,但非曲折的答案不适用于真实案例。这是一个扩展示例(不起作用),它说明了我实际尝试做的事情:

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!

)

I would like to see

我想看看

111
222
333

output.

输出。

回答by akf

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

考虑一个不太曲折的解决方案,这也产生了CCC你想要的。

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 forloop.

setlocal enabledelayedexpansion- 这将允许在您的 bat 期间使用任何环境变量设置,以便在您的for循环过程中进行修改。

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

set AAA=BBB, set BBB=CCC- 您的数据填充set语句

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 doblock. Likewise, if you specify %%i, use %%i in your doblock. Note that to get your environment variable to be resolved within the doblock of the forloop, you need surround it in !'s. (you don't need to in the inblock, as I originally posted - I have made that change in my edit).

for /F %%a in ('echo %AAA%') do echo !%%a!- 这告诉处理器循环,尽管只循环一次,并从括号中的命令运行中取出返回的第一个标记(空格和制表符的默认分隔符应用)并将其放入 var %%a(外部一个批次,一个 % 就可以了)。如果将该 var 指定为 %%a,则需要在do块中使用 %%a 。同样,如果您指定 %%i,请在do块中使用 %%i 。请注意,要dofor循环块内解析您的环境变量,您需要将其括在!'s 中。(您不需要在in块中,正如我最初发布的那样 - 我已经在我的编辑中进行了更改)。

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 inset 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 DDDvariables resolved, but then the doblock of your inner loop wouldnt have anything to resolve - you dont have any 111environment variables. With that in mind, you could simplify your loop with the following:

您的更新与此之间的区别在于您试图用 回显in集合中的环境变量in ('echo %%%i%'),但没有!用于延迟扩展设置变量的's。如果您使用in ('echo !%%i!'),您会看到您的BBBCCCDDD变量已解析,但是do您的内部循环块将无法解析 - 您没有任何111环境变量。考虑到这一点,您可以使用以下内容简化循环:

@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!)

回答by Piotr Dobrogost

How to expand a shell variable multiple times:

如何多次扩展shell变量:

@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

回答by paxdiablo

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.

我经常使用这个技巧来(例如)格式化%aaa%%x%特定大小(a la sprintf),但这是我第一次不得不进行双重间接访问。它之所以有效,是因为您没有发现"%%"当前 shell 级别吸收了额外的内容。

回答by wqw

This aaa.bat

这个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?

究竟是什么问题?

回答by Stephen Quan

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

OP 问题几乎适用于 Windows 10。需要一个小的更正才能正确形成ECHO命令。这是中间结果:

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 FORstatement and get the completed result:

然后我们将输出嵌套在另一个FOR语句中并获得完成的结果:

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

回答by james turner

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
)

回答by nik

Double indirection (which is a very apt way paxhas put it) reminds of C pointer de-referencing.
I doubt that is supported in the Windows command shell.

双重间接(这是一种非常恰当的方式pax)让人想起 C 指针取消引用。
我怀疑在Windows 命令外壳中是否支持。

Do you think the larger purpose you are targeting can be achieved with something easier;
maybe lesser of a code-golfapproach then the one contrived nicely by pax?

您是否认为可以通过更简单的方式实现您所瞄准的更大目标?
也许较少的代码高尔夫方法然后精心设计的方法pax