BAT-файл: содержимое переменной как часть другой переменной - PullRequest
5 голосов
/ 14 марта 2012

Предположим, у меня есть переменная a с содержимым " 123 " и переменная b123 с некоторым текстом в нем. Почему-то я хочу использовать переменную a как часть имени второй переменной. Примерно так:

SET a=123
SET b123=some_text_in_it
rem i want next line to output  "some_text_in_it"
echo %b%a%%

поэтому я хочу объединить текст с содержимым var и использовать полученную строку в качестве имени переменной, чтобы отобразить это содержимое. Пример выше не работает, и я понимаю, почему, возможно, мне нужно добавить какую-то группировку. Как это сделать, желательно в одну строку?

Ответы [ 3 ]

8 голосов
/ 14 марта 2012

Есть два распространенных способа для этого
CALL или DelayedExpansion

setlocal EnableDelayedExpansion
SET a=123
SET b123=some_text_in_it
rem i want next line to output  "some_text_in_it"
call echo %%b%a%%%
echo !b%a%!

Вариант CALL использует тот факт, что вызов будет повторно обрабатывать строку во второй раз, сначалавремя будет расширено только %a%, а двойное %% будет уменьшено до одного %
call echo %b123%
И на втором шаге %b123% будет расширено.
НоCALL техника медленная и не очень безопасная, поэтому DelayedExpansion следует отдавать предпочтение.

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

Редактировать: Метод для массивов, содержащих числа
Если вы работаете с массивами, которые содержат только числа, вы также можете использовать set /a получить к ним доступ.
Это намного проще, чем FOR или CALL, и работает также в блоках.

setlocal EnableDelayedExpansion
set arr[1]=17
set arr[2]=35
set arr[3]=77
(
  set idx=2
  set /a val=arr[!idx!]
  echo !var!
)
2 голосов
/ 17 марта 2012

Существует еще один способ выполнить задачу, который очень полезен, если обе переменные были назначены в пределах одного блока в скобках, который их расширяет. Решение аналогично ответу отложенного расширения Джеба, за исключением того, что вместо обычного расширения используется переменная FOR.

@echo off
setlocal enableDelayedExpansion

:: Define a linefeed value - only needed for last variant
set LF=^


:: The two blank lines above are critical to the definition of LF

(
  set A=123
  set B123=some_text_in_it

  rem ECHO !B%A%! will fail because A was assigned within the same block

  rem This works as long as A does not contain * or ?
  for %%A in ("!A!") do echo !B%%~A!

  rem This works as long as A does not start with EOL character (; by default)
  for /f "delims=" %%A in ("!A!") do echo !B%%A!

  rem This will never fail because it disables EOL by setting it to a linefeed
  for /f eol^=^%LF%%LF%^ delims^= %%A in ("!A!") do echo !B%%A!
)

Можно также использовать трюк CALL, но сравнительно он очень медленный и ненадежный - см. ПОЗВОНИТЕ меня, или лучше избегайте звонка .

Определение и использование переменной перевода строки обсуждается на Объясните, как работает взлом переменной новой строки dos-batch .

Настройка EOL для перевода строки подробно описана в КАК: FOR / F Отключение EOL или использование кавычки в качестве разделителя . Использование переменной LF вместо встраивания перевода строки в операторе FOR является лишь расширением техники. Это делает код более читабельным.

EDIT
Более простой способ безопасно использовать метод FOR для любого допустимого значения - установить для EOL знак равенства, поскольку ни одна пользовательская переменная не может содержать = в имени.

for /f "eol== delims=" %%A in ("!A!") do echo !B%%A!
2 голосов
/ 16 марта 2012

Лучшая причина «использовать переменную как часть имени второй переменной» - получить доступ к элементам массива (вектора и матрицы) через переменную индекса. Хотя это в точности то же самое, что и в приведенном выше примере, выглядит гораздо яснее:

setlocal EnableDelayedExpansion
set i=123
set v[123]=Value of element 123
call echo %%v[%i%]%%
echo !v[%i%]!

Хотя CALL медленнее, чем Delayed Expansion, как сказал выше Джеб, он может быть вложен несколько раз, позволяя использовать вторую (или более глубокую) косвенность для доступа к элементам массива. Эта функция может использоваться в сложных структурах данных, таких как связанные списки. Например:

set i=123
set v[123]=456
set w[456]=Value of element 456
call call echo %%%%w[%%v[%i%]%%]%%%%

РЕДАКТИРОВАТЬ : Почему-то я не понимаю, версия последней команды с отложенным расширением не работает должным образом:

call echo !w[%%v[%i%]%%]!
...