Почему CALL печатает сообщение помощи GOTO в этом скрипте? И почему после этого команда выполняется дважды?
Вот одна интересная тема. И я попытался поиграть с двумя обсуждаемыми там вещами.
- Вы можете получить доступ к меткам со специальными символами с двойным расширением.
- Метки, содержащие
/?
не может быть использован, потому чтоGOTO
а такжеCALL
печатает их сообщения помощи вместо выполнения.
И вот результат:
@echo off
setlocal enableDelayedExpansion
set "label=/?"
call :%%label%%
echo == Test message to check if the CALL or GOTO ( or neither ) command is executed ==
exit /b 0
:/?
echo == CALL or GOTO has been executed ==
exit /b 0
И вывод:
Directs cmd.exe to a labeled line in a batch program.
GOTO label
label Specifies a text string used in the batch program as a label.
You type a label on a line by itself, beginning with a colon.
If Command Extensions are enabled GOTO changes as follows:
GOTO command now accepts a target label of :EOF which transfers control
to the end of the current batch script file. This is an easy way to
exit a batch script file without defining a label. Type CALL /? for a
description of extensions to the CALL command that make this feature
useful.
== Test message to check if the CALL or GOTO ( or neither ) command is executed ==
== Test message to check if the CALL or GOTO ( or neither ) command is executed ==
И код после CALL
выполняется дважды??
РЕДАКТИРОВАТЬ
Это еще более необъяснимо для меня:
@echo off
setlocal enableDelayedExpansion
set "label=/?"
set /a x=1
call :%%label%% >nul
set /a x=x+1
echo ---
echo -%x%-
echo ---
exit /b 0
:/?
echo == CALL or GOTO has been executed ==
echo == first argument : %1 ==
exit /b 0
Выход:
---
-3-
---
Код после вызова CALL
наверняка выполняется дважды, но вывод первого запуска может быть перенаправлен в одну и ту же строку?
2 ответа
Я всегда удивляюсь, что ты все еще находил вещи, которые никогда не приходили мне в голову, чтобы проверить.
Вопреки Аасини, я не верю этому :/?
действует здесь как действительный ярлык.
Еще это должно найти такой ярлык.
Я полагаю, что CALL
Команда внутренне состоит из функции толкателя стека, а затем просто использовать GOTO
прыгать на этикетку.
И так как вы используете позднее расширение /?
не обнаружен CALL
сама команда, но GOTO
команда.goto
показывает только справочную информацию и закончил, но как call
уже поместил файловую позицию в стек, он работает как вызов этой файловой позиции и позже возвращается в то же место!
set "help=^ /?"
call :myLabel%%help%%
Это показывает также помощь, как GOTO :myLabel /?
сделал бы.
Но этот не
set "help=/?"
call :myLabel %%help%%
Я полагаю, GOTO получает только метку, проанализированную CALL, остальные параметры перемещаются в %1, %2, ...
И это может объяснить, почему только метка может использовать отложенное расширение два раза.
@echo off
setlocal EnableDelayedExpansion
set "label=myLabel"
set "pointer=^!label^!"
call :!pointer!
exit /b
:myLabel
echo it works
Интересно! Первый код может быть уменьшен до:
@echo off
setlocal
set "label=/?"
call :%%label%%
echo == Test message to check if the CALL or GOTO ( or neither ) command is executed ==
и по-прежнему показывают тот же вывод, то есть он ведет себя так же, как этот код:
@echo off
setlocal
call :/?
echo == Test message to check if the CALL or GOTO ( or neither ) command is executed ==
где call :/?
является и командой вызова, и допустимой меткой, И учитывая :/?
действительный ярлык. Вот Это Да!
Почему отображается справка GOTO? Без понятия!!!
РЕДАКТИРОВАТЬ: Дополнительные тесты
Этот код:
@echo off
setlocal
set "label=/?"
set i=0
call :%%label%% & echo Command in same line: i=%i%
set /A i+=10
echo == Test message == i=%i%
сначала покажите экран справки GOTO, а затем:
== Test message == i=10
Command in same line: i=0
== Test message == i=20
но если EnableDelayedExpansion
добавлено и %i%
изменен !i!
в строке вызова он показывает:
== Test message == i=10
Command in same line: i=10
== Test message == i=20
как и ожидалось"...
РЕДАКТИРОВАТЬ № 2
Тест ниже показывает, что call :%%label%%
Команда НЕ сообщает об ошибке ERRORLEVEL=1 при ошибке "label not found":
@echo off
setlocal
set "label=/?"
call :notFound
echo Label not found: ERRROLEVEL = %ERRORLEVEL%
ver > NUL
echo Reset errorlevel: ERRROLEVEL = %ERRORLEVEL%
call :%%label%%
echo == Test message == ERRROLEVEL = %ERRORLEVEL%