Почему CALL печатает сообщение помощи GOTO в этом скрипте? И почему после этого команда выполняется дважды?

Вот одна интересная тема. И я попытался поиграть с двумя обсуждаемыми там вещами.

  1. Вы можете получить доступ к меткам со специальными символами с двойным расширением.
  2. Метки, содержащие /? не может быть использован, потому что 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%
Другие вопросы по тегам