Переменные среды в пакетных файлах раскрываются при разборе строки. В случае блоков, разделенных круглыми скобками (как ваш if defined
), весь блок считается «строкой» или командой.
Это означает, что все вхождения% FOO% заменяются своими значениями до запуска блока. В вашем случае ни с чем, так как переменная еще не имеет значения.
Чтобы решить эту проблему, вы можете включить отложенное расширение :
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%
в обоих IF
операторах подставляется при чтении первого оператора IF, так как он логически включает в себя тело IF
оператора, который является составным оператором. Таким образом, IF внутри составного оператора действительно сравнивает «до» с «после», которое никогда не будет равным. Аналогично, следующий пример не будет работать должным образом:
set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%
в том смысле, что он не будет создавать список файлов в текущем каталоге, а просто установит 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%
!
, используйте^^^!
(избегайте дважды). В противном случае функция «отложенного расширения» сожрет ее.Такое же поведение также происходит, когда команды находятся в одной строке (
&
это разделитель команд):Объяснение Джои мое любимое. Однако обратите внимание, что
enabledelayedexpansion
это не работает в Windows NT 4.0 (и я не уверен в Windows 2000).О вашей последующий вопрос, нет, это не представляется возможным
EnableDelayedExpansion
безsetlocal
. Однако исходное поведение, которое шло против вас, может быть использовано для решения этой второй проблемы: хитрость заключается в том, чтобыendlocal
на той же строке, где вы снова устанавливаете значения нужных вам переменных.Вот ваш
test.bat
модифицированный:Но вот еще одно решение этой проблемы: используйте процедуру в том же файле вместо встроенного блока или внешнего файла.
источник
Если это не работает таким образом, вы, вероятно, отложили расширение переменной среды. Вы можете отключить его
cmd /V:OFF
или использовать восклицательные знаки внутри, если:источник
Это происходит потому, что ваша строка с
FOR
командой оценивается только один раз. Вам нужен какой-то способ переоценить его. Вы можете смоделировать отложенное расширение с помощьюCALL
команды:источник
Стоит отметить, что он работает, если это одна команда на одной строке.
например
на самом деле
FOO
будет 1. Вы можете сделать еще одну проверку, такую как:Эй, я никогда не говорил, что это красиво. Но если вы не хотите связываться с setlocal или с отложенным расширением бизнеса, это быстрый обходной путь.
источник
Иногда, как и в моем случае, когда вам нужно быть совместимым со старыми системами, такими как старые серверы NT4, где отложенное расширение не работает или по какой-то причине не работает, вам может потребоваться альтернативное решение.
В случае, если вы будете использовать Delayd Expansion, также рекомендуется включить как минимум регистрацию в пакете:
Если вам просто нужен более читабельный и простой подход, вот альтернативные решения:
который работает так:
и еще одно чистое решение cmd:
это работает так:
и это полное, ЕСЛИ ТОЛЬКО Синтаксическое решение:
это работает так:
источник