Подтвердить что ты не робот

Незначительная проблема с областью в файле .bat

Я пишу простой файл .bat, и я столкнулся с каким-то странным поведением. Есть пара мест, где мне нужно сделать простой if/else, но код внутри блоков, похоже, работает некорректно.

Вот простой пример, демонстрирующий ошибку:

@echo off

set MODE=FOOBAR

if "%~1"=="" (
  set MODE=all
  echo mode: %MODE%
) else (
  set MODE=%~1
  echo mode: %MODE%
)
echo mode: %MODE%

Выход, который я получаю:

C:\>test.bat test
mode: FOOBAR
mode: test

Почему эхо внутри блока кода не получает новое значение переменной? В фактическом коде, который я пишу, мне нужно создать несколько переменных и ссылаться на них в пределах области if/else. Я мог бы переключить это, чтобы использовать метки и gotos вместо if/else, но это не кажется почти таким же чистым.

Что вызывает такое поведение? Есть ли какой-то предел для переменных в кодовых блоках?

4b9b3361

Ответ 1

Вы столкнулись с проблемой статической переменной cmd. Переменная MODE оценивается только один раз. Вы можете увидеть это, если вы опустите строку @echo off.

Из множества /? документация:

Наконец, поддержка расширенного расширения переменной среды был добавлен. Эта поддержка всегда отключено по умолчанию, но может быть включено/отключено с помощью команды /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%

в том, что он НЕ составит список файлов в текущем каталоге, но вместо этого просто установите СПИСОК переменная к последнему найденному файлу. Опять же, это потому, что% 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%

Ответ 2

setlocal EnableDelayedExpansion

включит флаг/v

Ответ 3

Похоже, что чтение и запись используют разные правила определения области видимости.

Если вы удалите эту строку

set MODE=FOOBAR

он будет работать, как ожидалось. Таким образом, вам, вероятно, потребуется сложная серия, если if/elses, чтобы получить переменные, которые вам нужно.