Как развернуть переменную оболочки 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
)