Как развернуть переменную оболочки CMD дважды (рекурсивно)

Используя командную строку Windows XP CMD, я могу дважды расширять переменную следующим образом:

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

будет эхо CCC. То есть AAA был расширен до строки BBB, а затем переменная BBB была расширена до CCC.

Это не работает из пакета script (т.е. файла .cmd). Изменение %%AAA%% на %%%AAA%%% или %%%%AAA%%%% тоже не работает.

Любая идея, как я могу достичь этого изнутри script, а именно, чтобы развернуть переменную AAA в строку CCC?

Позднее редактирование

Ответы, опубликованные для моего приведенного примера, работают, но нечеткий ответ не работает для реального случая. Вот расширенный пример (который не работает), который иллюстрирует то, что я на самом деле пытался сделать:

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!

)

Я хотел бы видеть

111
222
333

выход.

Ответ 1

Размышляя о менее извилистом решении, вы тоже получаете CCC.

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

изменить

чтобы проанализировать этот ответ:

setlocal enabledelayedexpansion - это позволит использовать любую переменную окружения во время вашей летучей мыши, которая будет изменена в процессе вашего цикла for.

set AAA=BBB, set BBB=CCC - операторы данных set

for /F %%a in ('echo %AAA%') do echo !%%a! - Это указывает процессору на цикл, хотя и только один раз, и вынимает первый токен, который возвращается (по умолчанию используется разделитель пространства и вкладка) из запуска команды в parens и помещает ее в var %% a (вне пакета, один% будет делать). Если вы укажете, что var как %% a, вам нужно использовать %% a в вашем блоке do. Аналогично, если вы укажете %% i, используйте %% я в своем блоке do. Обратите внимание, что для того, чтобы ваша переменная среды была разрешена в блоке do цикла for, вам нужно окружить ее в !. (вам не нужно в блоке in, как я уже писал - я сделал это изменение в своем редактировании).

изменить

Вы были очень близки к вашему обновленному примеру. Попробуйте это следующим образом:

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

Разница между вашим обновлением и этим заключается в том, что вы пытались повторить переменную окружения в in с in ('echo %%%i%'), но без ! для отложенного расширения заданных переменных. Если бы вы использовали in ('echo !%%i!'), вы бы увидели, что ваши переменные BBB, CCC и DDD решены, но тогда блок 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!)

Ответ 2

Как развернуть переменную оболочки несколько раз:

@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

выход:

Variable value before expansion: second
Variable value after expansion: fifth

Ответ 3

Следующий (мучительный) подход, похоже, работает нормально:

    @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

Он выводит:

ccc

по желанию.

Я часто использовал этот трюк для (например) формата %aaa% в %x% до определенного размера (a la sprintf), но это первый раз, когда мне пришлось делать двойное косвенное обращение. Это работает, потому что вы не найдете лишнего "%%", всасываемого текущим уровнем оболочки.

Ответ 4

Этот aaa.bat

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

выходы

c:>ccc

В чем именно проблема?

Ответ 5

Это несколько датированный вопрос, но, что интересно, ответ теперь проще. Я запускаю эти сценарии в Windows 10:

setlocal enabledelayedexpansion
set AAA=BBB
set BBB=CCC
echo !%AAA%!

выходы

CCC

В расширенной версии это работает:

setlocal enabledelayedexpansion
set LIST=BBB CCC DDD
set BBB=111
set CCC=222
set DDD=333
for %%i in (%LIST%) do (
    echo !%%i!
)

выходы

111
222
333

Ответ 6

Двойное косвенное (это очень удобный способ pax положил его) напоминает C-указатель de-referencing.
Я сомневаюсь, что это поддерживается в командной оболочке Windows.

Считаете ли вы, что более масштабная цель, на которую вы нацеливаетесь, может быть достигнута с помощью чего-то более легкого,
может быть, меньше подхода code-golf, а тот, который отлично нарисован pax?

Ответ 7

кажется, что проще всего создать крошечный файл temp, чтобы установить переменную по своему усмотрению. что-то вроде этого должно работать:

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
)