Странная проблема с областью в .bat файле - PullRequest
17 голосов
/ 20 ноября 2008

Я пишу простой .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. Я мог бы переключить это, чтобы использовать метки и переходы вместо if / else, но это не кажется таким уж чистым.

Что вызывает такое поведение? Есть ли какое-то ограничение на переменные внутри блоков кода?

Ответы [ 3 ]

26 голосов
/ 20 ноября 2008

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

Из набора /? документация:

Наконец, поддержка отложенного расширения переменной среды имеет был добавлен Эта поддержка всегда по умолчанию отключено, но может быть включается / отключается с помощью команды / 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, которое является сложное утверждение. Итак, ЕСЛИ внутри составного оператора действительно сравнивая «до» с «после» который никогда не будет равным. Так же, следующий пример не будет работать как Ожидаемый результат:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%

в том смысле, что он НЕ будет составлять список файлы в текущем каталоге, но вместо этого будет просто установить список переменная до последнего найденного файла. Опять же, это потому, что% LIST% расширен только один раз, когда ЗА заявление читается, и в то время переменная 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 голосов
/ 10 сентября 2009

setlocal EnableDelayedExpansion

активирует флаг / v

0 голосов
/ 20 ноября 2008

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

Если исключить эту строку

set MODE=FOOBAR

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

...