(Пакет Windows) Перейти внутри, если блок ведет себя очень странно - PullRequest
17 голосов
/ 13 декабря 2011

Если взять следующий фрагмент кода Windows и запустить его:

echo foo
if 1 == 1 (
    echo bar
    goto asdf
    :asdf
    echo baz
) else (
    echo quux
)

Вывод, который я ожидаю получить:

foo
bar
baz

Но вместо этого я получаю:

foo
bar
baz
quux

Если я закомментирую строку goto asdf, это даст ожидаемый результат.Строка echo quux никогда не должна подвергаться изменению, так почему существование goto вызывает это?

ОБНОВЛЕНИЕ: Для чего стоит, вот обходной путь, который правильно делает то, что яизначально предполагалось:

goto BEGIN

:doit
    echo bar
    goto asdf
    :asdf
    echo baz
    goto :EOF

:BEGIN

echo foo
if 1 == 1 (
    call :doit
) else (
    echo quux
)

Однако это не отвечает на мой первоначальный вопрос.

Ответы [ 3 ]

28 голосов
/ 13 декабря 2011

Цель CALL или GOTO никогда не должна быть внутри оператора блока в скобках.Это можно сделать, но, как вы видите, результаты, вероятно, не будут такими, как вы хотите.

Вся конструкция IF (...) ELSE (...) анализируется и загружается в память передлюбая из них обрабатывается.Другими словами, это логически рассматривается как одна строка кода.После его анализа CMD.EXE ожидает возобновления синтаксического анализа, начиная со следующей строки после конструкции IF / ELSE.

После фазы анализа сложная команда выполняется из памяти.Предложение IF обрабатывается правильно, а предложение ELSE пропускается правильно.НО в предложении IF (true) вы выполняете GOTO :asdf, поэтому CMD.EXE должным образом начинает поиск метки.Он начинается в конце IF / ELSE и сканирует до конца файла, возвращается к началу и сканирует, пока не найдет метку.Возможно, метка находится в вашем предложении IF, но сканер меток ничего не знает об этой детали.Поэтому, когда сложная команда завершает выполнение из памяти, пакетная обработка возобновляется с метки, а не с конца комплексного IF / ELSE.

Таким образом, в этот момент пакетный процессор видит и выполняет следующие несколько строк

    echo baz
) else (
    echo quux
)

baz повторяется, как и quux.Но вы можете спросить: «Почему ) else ( и / или ) не генерируют синтаксическую ошибку, поскольку они теперь не сбалансированы и больше не анализируются как часть более крупного оператора IF?

Это происходит из-закак обрабатывается ).

Если при открытии ) есть активное открытие (, то ) обрабатывается так, как вы ожидаете.

Но еслисинтаксический анализатор ожидает команду и находит ), когда нет активного открытия (, тогда ) игнорируется и все символы в оставшейся части строки игнорируются! Фактически ) теперь работает какОперативное заявление.

7 голосов
/ 13 декабря 2011

Все, что находится внутри набора скобок, считается одной строкой, обрабатывается, интерпретируется и выполняется в одном обращении.Ваш сценарий достигает goto asdf и выпрыгивает из этого блока / строки.На метке :asdf скобка отсутствует, поэтому он начинает читать строки одну за другой.Он достигает else, но между :asdf и else нет if, поэтому он игнорирует его.

Чтобы избежать подобных проблем, я всегда использую goto или call на if и for операторы, а не блоки.Это решает проблемы с дальнейшими операторами goto, а также решает множество проблем с переменными.

Для использования goto:

echo foo
if 1 == 1 goto bar
echo quux
goto nextbit

:bar
echo bar
goto asdf
:asdf
echo baz

:nextbit
:: more script...

Или для использования call:

echo foo
if 1 == 1 (call :bar) else (call :quux)
:: more script...
exit /b

:bar
echo bar
goto asdf
:asdf
echo baz
exit /b

:quux
echo quux
exit /b
0 голосов
/ 14 ноября 2017

В этом случае выясняется, что это связано с плохим вложением и структурой цикла внутри оператора IF, как четко объяснено https://stackoverflow.com/users/1012053/dbenham выше.

Тем не менее, я выяснил другое подобное соображение из-за этой проблемы ... Пожалуйста, обратите внимание на следующую проблему и последующее решение здесь: ". В это время было неожиданно" сгенерировано из строки пакетного сценария ", если существует [файл] (...

Решением была просто обработка '(' и ')' в строках ECHO внутри блока операторов IF.

Суть в том, что можно рассматривать обработку специальных символов как возможный источник проблемы при устранении неполадок в операторах IF (и, возможно, FOR).

НТН

...