【问题标题】:Why won't portions of the code from this batch file execute. Please explain the GOTO function为什么此批处理文件中的部分代码不会执行。请解释 GOTO 功能
【发布时间】:2014-06-07 12:16:50
【问题描述】:

我正在玩一些批处理文件并且遇到了一些问题。根据一个网站:

要退出批处理脚本文件或退出子例程,请指定 GOTO:eof this 将控制转移到当前批处理文件的末尾或末尾 的当前子程序

那么,考虑到这个定义,为什么这两个代码的某些部分不能执行:

第一个:

:Loop
echo I am in a loop.
GOTO:eof

Echo Hello

Goto Loop

echo Finish

pause

唯一打印出来的是:我在一个循环中。没有其他东西打印出来。

第二个:

Echo Hello

Goto Loop

echo Finish

pause

:Loop
echo I am in a loop
GOTO:eof

echo Finish 不打印。为什么?

另外,您能简单说明一下 Goto 使用和子程序之间的区别吗?

谢谢

更新:在 Google 上搜索其他内容时,我发现了这个:Using CALL for labels in a batch script,我猜它回答了这个问题,但我仍然需要详细说明,比如

1) 何时使用 GOTO,何时使用 Call? (我想这与我上面关于子程序和 GOTO 之间差异的问题有关)

2)对于第一个代码,为什么会出现句子:“I am in a loop”。打印/得到回显,当它从未被调用/指示执行时?

2b) 该部分如何仅在被调用时才执行?

更新 2:

好吧,我怎样才能让这样的事情起作用?

@echo off

    echo main line
    call :loop
    call :another
    call :loop
    echo main line again
    goto :eof

:loop
    echo inside the subroutine

:another
   echo hi!

【问题讨论】:

  • 为什么你写的代码却说“我在一个循环中”,而你却不是?!当您已经在文件末尾时,编写 Goto :eof 没有任何好处
  • 您需要停顿很多次并自己弄清楚发生了什么,因为在您的 cmets 中,您正在对正在发生的事情做出一些非常疯狂的假设。暂停一下,预测会发生什么,弄清楚它在做什么。您甚至在代码中包含疯狂的假设,例如调用标签循环,建议您假设它会循环。你真的需要做一些故障排除和分解。你甚至会问为什么当你有一个标签和一些代码时,它会运行代码。编写一个简单的标签和代码程序,你会学到更多。
  • -1 您刚刚写道,您的批处理文件中有另一行(一些 cmd /k)导致了一些奇怪的行为,您声称您认为自己得到了但您不认为它是很重要,所以你错过了。至少你是诚实的,但这个问题根本没有很好地提出(或经过深思熟虑)

标签: windows batch-file cmd dos


【解决方案1】:

goto 命令的任务是通过跳转到现有标签来更改要执行的下一行内容。标签后的第一行将是要执行的下一行。与代码中使用了多少个gotos 无关,如果执行到达文件末尾(包括goto :eof)或到达exit /b,则批处理文件的执行结束。

要使用子程序,必须使用call :label 命令。执行此命令时,将创建第二行执行。第一行(调用代码)暂停,直到第二行(子程序)结束,第一行的执行将在call 之后的第一个命令处继续执行。

子程序何时结束执行?

在其他语言中,子程序有一个起点和一个终点,在它的声明中使用某种语法来界定哪些代码属于子程序。

批处理文件不是这种情况。子程序只有一个起点,即被调用的标签,当到达另一个标签时,执行不会结束。

子程序在其执行行结束时结束,当执行exit /b 或到达批处理文件的末尾时会发生这种情况。在这两种情况下,子程序的执行行都结束,调用代码的执行行继续。

当然,在任何情况下,如果执行exit 命令(没有/b 开关),当前批处理和当前控制台都会关闭。

问题

1) 何时使用goto,何时使用call?这取决于。它们应该在需要时使用,这取决于要解决的问题、解决问题的想法以及它们的编码方式。

2) 批处理代码中的标签不定义函数,也不绑定任何东西。他们在代码中定义了可以跳转或调用的点。但是它们不会干扰代码执行,因此,如果在那一刻(或多或少)不需要它们,它们会被解析、丢弃,并且该过程在下一行继续。标签不是保护/阻止代码的障碍。因此,在您的代码中,初始标签被跳过,您的第一个可执行行是echo 命令。之后,goto:eof 结束批处理文件的执行。

2b) 如果您不想在没有被调用的情况下执行该行,请确保除非被调用/跳转到,否则无法到达该行。

@echo off
    echo main line
    call :loop
    echo main line again
    goto :eof

:loop
    echo inside the subroutine

【讨论】:

  • 谢谢。行。因此,您将标签添加到底部以便它可以工作。我还看到您使用Call。我在顶部添加了:loop 并注释掉了call 部分和:loop 下的echo 确实打印了。因此,似乎将其添加到底部是解决方案。但是当一个标签有多个标签时会发生什么?请务必查看上面的 Update 2。仅调用前两个标签。第三个,与第一个相同,不执行。我怎样才能让这样的场景发挥作用?
  • @Rolo,您发布的代码不像您说的那样运行。你有三个电话,三个工作。此代码的输出是 main, subroutine, hi, hi, subroutine, hi, main ,即主线,调用 :loop 回显 sub 并继续执行直到文件结束(回显 hi),调用 :another 回显 hi,调用 @987654344 @ 再次呼应 subhi,以及新的 main。
  • @Rolo,记住子程序不会在下一个标签处结束,而是在到达文件结尾或exit /b 时结束。标签标记可以跳跃或被调用的点。当使用gotocall 时,它们会被搜索并使用,但其余时间它们是否存在几乎没有区别。
  • @Rolo 当您在“更新 2”中说“仅调用前两个标签”时,您在说什么。只有两个标签 + :eof 的隐含标签 您的第一个标签是 :loop 而您的第二个标签是 :another。我想你的意思是只运行前 2 个调用语句,但事实并非如此。
  • 您对输出的看法是正确的。在:another echo hi! 之后,我有另一行与cmd /k,因此 cmd 框不会关闭。我没有把它放在这里,因为它并不重要。但是现在我看到你所说的关于:loop 回显 sub 并继续执行直到文件结尾(即:another),我现在明白为什么我只得到你提到的输出的前三行。我以为是另一个 Call 被处决了。
【解决方案2】:

转到那里并没有回来。如果您想结束一个程序或做某事并结束一个程序,那很好。它也可以用于迭代。并且为了运行一些代码就像一个子程序。

调用会去那里并返回。所以这就像 goto 然后做一些代码,然后有另一个 goto 回到原来的位置。

如果您想进行迭代,Goto 也可以这样做。创建一个循环。

但是标签必须在 Goto 之前

例如

:xyz
echo abc
goto :xyz

^^^ 那是一个循环。

如果你想在一个批处理文件中运行一个批处理文件,你通常想要并且意味着使用调用,否则它将无法继续。

而你似乎在某一时刻想知道为什么

:xyz
echo abc

为什么它与 abc 相呼应。当您认为没有什么可以指示它运行该子程序时,它是一个不一定用作子程序的标签。

您可以将它用作子例程,但要做到这一点,您需要确保除非被调用,否则永远不会到达它。

goto :eof
:xyz
echo abc

^^^ 那是一个子程序,你可以调用它。

现在当你想像子程序一样运行 xyz 时,你会在 goto:eof 之前说call xyz

关于你的最新更新..

你想要多个子程序

您的问题是您的所谓子例程之间没有 goto :eof,因此它运行一个,然后运行以下子例程。

:abc

:def

:ghi

然后你尝试转到 abc 或调用 abc,那么它将通过所有这些..

你需要在每个你想成为子例程的末尾添加一个 goto :eof。

你不一定需要 goto :eof 在最后,因为那是文件的结尾。

:abc

goto :eof

:def

goto :eof

:ghi

将其应用于您的代码

@echo off

    echo main line
    call :loop
    call :another
    call :loop
    echo main line again
    goto :eof

:loop
    echo inside the subroutine
    goto :eof
:another
   echo hi!

这给出了我认为你想要的输出。 注意我添加到循环标签代码中的 goto :eof。

添加示例-

之前我没有在 abc 标签之前放置 goto :eof,这确实表明单独的标签不会使其成为子例程,但如果您希望 abc 像子例程,则在它之前放置 goto。在这个例子中我已经做到了。

REM 是一种注释方式,你可以在 cmd 提示符下试试。

REM YOU COULD PUT A LABEL HERE IT MAKES NO DIFFERENCE
echo main

goto :eof
:abc
goto :eof

:def

^^ 在那个程序中,这些“子例程”都没有运行,因为我没有调用它们,但是可以将代码放入并调用它们或转到它们。我没有费心在 :def 之后放置 goto :eof ,因为它是文件的结尾,但是这样做的一个有用的原因是如果您想在 :def 之后添加另一个子例程,例如:ghi 那么你会想要一个 goto :eof 在它们之间,因为你想要一个 goto :eof 在任何“子程序”之间。但是您永远不需要在文件末尾添加 goto :eof。

【讨论】:

  • 非常有帮助。这非常具有说明性。我仍然对最后一个标签(即:ghi 或:another)有点困惑,并且想知道它是否仍然不会在没有被调用的情况下执行,但是通过一些实验,我发现goto :eof 阻止了这种情况。虽然 eof 是文件结尾,但我出于某种原因认为它会进入文件的最后一行,但它实际上是在最后一行或最后一个字符之后,这才是真正的结尾。在您的 abc、def、ghi 示例中,为了防止 :abc 再次执行,我需要在其上方放置一个 goto :eof,并将所有其他代码放在其上方。
  • @Rolo Right reeof 即将结束。但是当你说“为了防止 :abc 再次执行,我需要在它上面放置一个 goto :eof ,以及在它上面的所有其他代码。”你并不完全清楚,听起来有些不对劲。因为在 abc 标签后面的代码,在这些示例中只执行一次,无论顶部有或没有 :eof,它都可以再次运行。在标签上方放置 goto :eof 是一种有用的设计模式,它将使确保该标签后面的内容仅在调用时执行。但是如果多次调用可以执行多次。所以,它会让它像一个子程序。
  • @Rolo 我添加了一个示例,让 'abc' 像一个子例程。
  • 谢谢。关于防止:abc再次执行(在已经被调用之后),我的意思是如果我有这样的代码:@echo off echo Hello Call :abc call:ghi :abc echo I belong to abc goto :eof :def echo I belong to def goto :eof :ghi echo I belong to ghi标签goto :eof之前的行:abc阻止它在未被调用时执行。
  • @Rolo 是的,即使不管其他代码如何,标签前的 goto :eof 也会阻止标签后的代码在未调用时执行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-15
  • 2017-03-07
  • 2021-08-15
  • 1970-01-01
  • 2012-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多