【问题标题】:Why CALL prints the GOTO help message in this script?And why command after that are executed twice?为什么 CALL 在这个脚本中打印 GOTO 帮助消息?为什么之后的命令会执行两次?
【发布时间】:2015-08-13 11:33:02
【问题描述】:

Here's one interesting thread。我试着玩弄那里讨论的两件事。

  1. 您可以通过双扩展访问带有特殊符号的标签。
  2. 不能使用包含/? 的标签,因为GOTOCALL 会打印它们的帮助消息而不是执行。

结果如下:

@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调用后的代码肯定执行了两次,但是第一次运行的输出可以重定向到同一行吗?

【问题讨论】:

  • 如果你在call 之后添加一个& pause,它会回显所有内容一次,暂停然后回显它之后 暂停!

标签: batch-file cmd


【解决方案1】:

我总是很惊讶,你仍然发现了我从未想过要测试的东西。

与 Aacini 不同,我不认为 :/? 在这里充当有效标签。
否则这应该找到这样的标签。

我假设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

【讨论】:

  • 对。后跟冒号的call 命令开始生成新的批处理上下文。批处理代码被加载到此上下文中,如果生成上下文的元素以冒号开头,则将其视为标签,并执行goto 以跳转到此标签。它被使用并表示here。出于好奇,定义了一个内部变量,仅用于在启用echo 时隐藏goto 执行。
  • @npocmaka,批处理代码无法访问。只是用作标志的内存地址。我在调试cmd 时看到了它,只是为了在发布上一条评论中链接的答案之前确定。
  • 好的。我回顾了这一点并得出结论,jeb 是对的,只有一个细节。他说“goto 根本失败”,但没有; goto :/? 的执行正确执行并显示 GOTO 帮助屏幕。 CALL 部分看不到 GOTO 部分的错误,所以它继续正常...
  • 很好的分析,提出了解释行为的简单规则。
  • @Aacini 谢谢,你说得对,goto :/? 不会失败,我会改文字
【解决方案2】:

有趣!第一个代码可以简化为:

@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 标准的“标签未找到”错误:

@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%

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-01
    • 1970-01-01
    相关资源
    最近更新 更多