Переменные окружения в пакетных файлах расширяются при разборе строки. В случае блоков, разделенных круглыми скобками (как у вас if defined
), весь блок считается “строкой” или командой.
Это означает, что все вхождения %FOO% заменяются их значениями до запуска блока. В вашем случае ни с чем, так как переменная еще не имеет значения.
Для решения этой проблемы можно включить delayed расширение:
setlocal enabledelayedexpansion
Задержанное расширение приводит к тому, что переменные, ограниченные восклицательными знаками (!
), будут вычисляться при выполнении, а не при разборе, что обеспечит корректное поведение в вашем случае:
if not defined BAR (
set FOO=1
echo Foo: !FOO!
)
help set
также подробно описывает это:
Наконец, добавлена поддержка расширения переменных окружения с задержкой. Эта поддержка всегда отключена по умолчанию, но может быть включена/выключена с помощью переключателя командной строки /V
в CMD.EXE
. См. раздел CMD /?
Расширение переменной окружения с задержкой полезно для обхода ограничений текущего расширения, которое происходит при чтении строки текста, а не при ее выполнении. Следующий пример демонстрирует проблему немедленного расширения переменной:
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "%VAR%" == "after" @echo If you see this, it worked
)
никогда не выводит сообщение, поскольку операторы %VAR%
в операторе both IF
заменяются при чтении первого оператора ПЧ, поскольку логически он включает тело оператора IF
, который является составным оператором. Таким образом, IF внутри составного оператора действительно сравнивает “до” с “после”, что никогда не будет равнозначно. Аналогично, следующий пример не будет работать, как ожидалось:
set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%
в том, что он not создаст список файлов в текущем каталоге, а вместо этого просто установит переменную LIST
в последний найденный файл. Опять же, это происходит потому, что %LIST%
расширяется только один раз при считывании оператора FOR
, и в это время переменная LIST
пуста. Таким образом, фактический цикл FOR, который мы выполняем:
for %i in (*) do set LIST= %i
который просто сохраняет установку LIST
в последний найденный файл.
Расширение переменных окружения с задержкой позволяет использовать другой символ (восклицательный знак) для расширения переменных окружения во время выполнения. Если включено отложенное расширение переменных окружения, приведенные выше примеры могут быть записаны следующим образом, чтобы работать по назначению:
set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "!VAR!" == "after" @echo If you see this, it worked
)
set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%