(Пакет 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).
НТН