(Пакет Windows) Goto внутри, если блок ведет себя очень странно

Если я возьму следующий фрагмент кода пакета 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
)

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

Ответы

Ответ 1

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

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

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

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

    echo baz
) else (
    echo quux
)

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

Это связано с тем, как обрабатывается ).

Если открыт ( открытый (, когда встречается ), тогда ) обрабатывается так, как вы ожидали.

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

Ответ 2

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

Чтобы предотвратить такие проблемы, я всегда использую 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

Ответ 3

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

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

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

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

НТН