10 Windows批处理之调用例程和bat文件
在前文中,我先容了标签和非顺序执行,这两者在本文中也起着重要作用。我将很快先容一个已经讨论过的下令的新变化,允许您创建和调用由标签界说的例程。不是简单地在标签之后将控制权交给代码,而是在例程执行后将控制权返回到调用它的位置。在编写更复杂、更风趣的bat文件时,您需要完全理解例程。在前面文章中,我先容了调用用其他语言编译的可执行文件的概念。我将在这里睁开讨论,描述一个bat文件调用另一个bat文件的不同技术。显然,您将了解最典范的调用类型,它将控制权返回给调用的bat文件。但是,您还将学习放弃对所调用的bat文件的控制的技术,以及如何生成第二个并行批处理进程。别的,您还将探索从例程或bat文件优雅退出的不同方法,无论是否利用返回代码。
call 下令及重新访问
在创建可调用的内部例程之前,必须了解利用标签的两个下令之间的异同。此中之一是call下令,在那边我们利用它来调用用其他语言编译的步调。另一个是goto下令,用于更改bat文件的执行流程。
为了比较和对比这两个下令,请回首之前先容的代码:
> con echo Before GOTO
goto :MyLabel
> con echo After GOTO
:MyLabel
> con echo After LABELgoto 下令跳过了中间的 echo 下令,导致如下输出:
Before GOTO
After LABEL为了演示对比,下面更改了代码中要调用的每个goto实例,包括goto下令和echo下令中的文本,而在这个非常简洁的bat文件中保留了其他所有内容。
> con echo Before CALL
call :MyLabel
> con echo After CALL
:MyLabel
> con echo After LABEL执行上面的bat文件,您将看到四行代码写入控制台,而不是某些人大概期望的三行代码。
Before CALL
After LABEL
After CALL
After LABELBefore CALL 的显示显然是立即执行的。call 下令临时将控制权交给标签后面的代码,导致显示 After LABEL。当这是一个 goto 下令时,此时 bat 文件在显示之后竣事。但是利用call下令,在 :MyLabel 和 bat 文件末端之间的所有内容执行之后,控制立即返回到call下令之后的下令。因此,显示 After CALL。
有些人大概期望执行在此时完成,但解释器接下来再次遇到 :MyLabel。我们不会调用它;相反,它只是一行代码。注意,我没有称它为下令,甚至也没有称它为语句。它只是一行代码,一个占位符,在这个上下文中,只不过是通往下一个下令的路径上的一个非常玄妙的减速带。解释器移到bat文件的最后一行,第二次显示文本 After LABEL。解释器找不到其他需要解释的下令,bat文件就完成了。
当 goto 下令放弃控制时,call 下令记着它从哪里来,并在它的业务完成后返回到谁人位置。现在我们有了一个可调用的内部例程,我们将用 call 下令调用这个例程。
调用内部例程
随着批处理代码变得越来越风趣,您大概希望从bat文件中的不同位置多次执行一段代码。比方,您大概希望多次调用可执行文件,或者您大概希望定期检查目录中是否有需要复制的文件。当我们用到交互式批处理时,你大概想要问用户一个题目并多次得到响应。
面对对一段代码进行多次调用的需求,新手步调员大概会采用剪切和粘贴的方式——在我极其挑剔的观点中,这是一种令人讨厌的选择。一个更好的解决方案是创建一个内部例程,并从多个位置调用它。您甚至可以将一些只调用一次的代码放入例程中,以便更好地组织您的bat文件。偶然直接运行一个标签是完全可以的,但更多时候,您需要创建一个只能通过调用它来调用的例程。
对于下面的练习,我们继续利用上面的代码,以便标签界说一个可调用例程。也就是说,执行流将调用例程,从中返回,并在再次进入该例程之前退出bat文件。为此,我需要一种方法来终止例程和bat文件。即 After LABEL的最终将不再显示。相反,我们期望有这三行输出:
Before CALL
After LABEL
After CALL下面的代码,看起来有点不同,正是这样做的:
> con echo Before CALL
call :MyLabel
> con echo After CALL
goto :eof & rem End of TestCall.bat
:MyLabel
> con echo After LABEL
goto :eof & rem End of :MyBabel
:AnotherLabel
> con echo This is Never Executed
goto :eof & rem End of :AnotherLabel在逐步执行代码之前,请注意三个goto :eof下令。如您所料,第一个跳转到文件的末端,制止bat文件。另外两种说法完全不同,是新出现的。
在初始的 echo 下令之后,call 下令会调用MyLabel的例程,该例程只包含两个下令。第一个是我们熟悉的 After LABEL 回显到控制台,第二个是 goto :eof 下令。因为这个下令是在标签被调用之后执行的,所以它竣事的不是文件而是例程,并且控制在调用下令之后返回到下令,在控制台写入 After CALL。最后,主 goto :eof 下令退出bat文件,因为解释器知道它不在例程中。
在:MyLabel例程中,转到:eof(或文件竣事)是不恰当的;它实际上更像是例行公事的竣事,但我们不要在语义上吹毛求疵。如果你删除这个goto :eof下令,控制将继续到 :AnotherLabel 的代码,然后返回主线逻辑。但是对于这个下令,下面的代码 :AnotherLabel 永远不会执行。
由于 goto :eof 下令有两种不同的用法,所以我通常在这些下令后面加上一个注释,界说它要终止什么,或者是例程的名称,或者是bat文件本身。我只是将rem下令放在一个&号后面,它在一行代码中将两个下令分隔开。从编程的角度来说,这是不须要的,但是这种做法极大地增强了代码的可读性,特殊是当例程比前面的示例更长、更复杂时。
调用Bat文件
短或重复的代码位是内部例程的最佳候选;您可以在bat文件的末端添加一个或多个例程,以创建一个组织良好的模块,您可以为此感到自豪。但偶然这些简短的代码并不那么短,或者它们非常有用,以至于您希望将它们提供给您编写的其他bat文件,甚至大概是其他人。这个场景没有利用例程,而是调用一个bat文件调用另一个bat文件。比方,您可以创建一个bat文件来处理日记记录,并从多个其他bat文件调用它。
从一个bat文件执行另一个bat文件的工作方式与执行内部例程略有不同。但首先,让我们回到前面的编译步调是如何执行的。当解释器遇到一行只是可执行文件名称的代码时,它调用可执行文件。因此,这个“下令”执行步调:D:\Batch\10\MyProg.exe。
步调完成其任务后,控制返回到bat文件。您大概期望对bat文件的调用以同样的方式工作,但是遗憾的是,事实并非云云。然而,下面的代码行确实执行了被调用的bat文件,但是利用了一个巨大的bat:call D:\Batch\10\CalledBat.bat。
总而言之,无论是调用bat文件照旧调用另一种语言的编译可执行文件,您都可以利用call下令或省略它,但这是有区别的。在调用可执行文件时,这两种技术实际上是相同的。在调用同类bat文件时,调用下令确保将控制权返回给调用者。如果没有下令,控制就永远不会返回。
因为我从来没有发现不返回的bat文件调用有什么用途,所以我总是倾向于忽略可执行文件的调用下令,而将其用于bat文件。一个优点是,一眼就能看出调用的是什么类型的文件。
在我职业生涯的早期,当我无法弄清楚为什么我的bat文件制止执行时,我了解到调用下令关于 bat文件的须要性。没有挂起或中止消息;它就这么停了。更复杂的是,我的故障排除可以集中在所谓的bat文件上。过了好一会儿,我才注意到谁人丢失的 call 下令,更重要的是,我明白了它的重要性。但这并不是call下令的唯一特性。
调用标签注意事项
在前文中,我提到可以在goto下令的参数中将冒号从标署名称中去掉,尽管猛烈建议包括它。利用call下令,在调用界说内部例程的标签时总是需要冒号。
这种明显的不一致大概没故意义,除非您思量到goto下令只涉及到其bat文件中的标签,而call下令调用其bat文件内部和外部的实体。效果是,当尝试调用 :MyLabel 而不带冒号时,会发生一些非常意想不到的事变:call MyLabel。
冒号会告诉解释器调用内部例程,但解释器却试图调用外部文件。首先,它在当前目录中查找可执行文件,如MyLabel.com或MyLabel.exe。然后,它在当前目录中查找MyLabel.bat和其他一些具有此文件名的可执行文件类型。然后,它遍历path变量中的所有目录,拼命寻找任何名为MyLabel的可以执行的内容。如果没有找到这样的文件,解释器将不会查找该名称的标签,纵然 :MyLabel 是bat文件中的有效标签;相反,它会生成一个错误。
当利用goto或call下令导航到标签时,为了保持一致性,请务必利用冒号。
重要:
当没有找到标签时,goto下令会中止进程。call下令更容易理解一些。当它的参数是一个无效的标签时,它们都写出一条错误消息,但是调用下令也将errorlevel设置为1。如果您选择不询问返回代码,则该过程将若无其事地继续进行,就似乎什么都没有发生一样。
启动Bat文件
偶然,您大概希望启动或生成一个bat文件作为一个新进程。也就是说,您大概希望启动另一个bat文件,但不希望解释器在继续之前等待它完成。比方,您可以并行执行多个进程以加速总体处理时间。您可以剥离出一个非关键但耗时的任务,比如一个日记记录进程,让它在自己的时间内执行。在后文中,我将讨论如何主动 kill 和重新启动挂起的进程。为了实现这一点,我将把容易挂起的进程作为一个独立的bat文件生成,并从主bat文件监视它。
要启动或生成一个bat文件,只需利用start下令代替call下令:start D:\Batch\10\LaunchedBat.bat。
该下令创建第二个下令或DOS窗口,此中文件 LaunchedBat.bat 与启动它的bat文件同时执行。
exit 下令
您大概会想到,exit 下令退出例程、bat文件或整个执行,它甚至可以设置返回代码。它在功能上与 goto :eof 下令有重叠,但我很快就会展示一个重要的区别。
不带参数的exit下令会突然竣事整个进程。遗憾的是,第二个echo下令不会被执行:
> con echo The meaning is Life is...
exit
> con echo ... %meaningOfLife%第一个echo下令将其消息写入控制台,但是exit下令在您可以读取它之前关闭了窗口。无论在哪里调用退出下令,都会发生这种环境——在高级bat文件中,在被调用的bat文件中,甚至在任一类型bat文件中的例程中。
然而,文档不清楚B代表什么,但对我来说,它代表break,因为下面的下令从被调用的代码中跳出,无论是被调用的bat文件照旧bat文件中的例程:exit /B。
该下令只有在高级bat文件的主逻辑中调用时才退出整个进程。它不会改变errorlevel,逻辑上等同于 goto :eof。这两个下令都是有效的,其用法通常取决于个人偏好。我利用的是 goto :eof下令,但只在不需要返回代码的环境下利用。
在前面的文章中,我们先容过基本中止逻辑,但将其解释留到后面,也就是现在。
:Abort
echo The Process is aborting
exit /B 1这个退出下令的行为与 exit /B 类似,但有一个破例。当控制返回到调用代码的位置时,该选项后面的下令的数字参数变成errorlevel中包含的新值。简而言之,该下令离开bat文件或例程并返回退出或返回代码。在前面的例子中,返回码是1。但是,如果没有检测到错误,则bat文件的主逻辑大概以将返回代码设置为0竣事:exit /B 0。
如果检测到致命错误,主线逻辑中的 goto :Abort 下令将把解释器引导到中止逻辑。必须利用 goto 下令,因为 call 下令会将中止逻辑视为被调用的例程;将设置错误级别,但控制权将返回到致命错误的位置。但是当利用goto下令导航到标签时,不会调用例程;它仍然被认为是在主线逻辑中,并且exit下令竣事了bat文件,而不是一个例程。
为了更灵活,你可以为退出代码创建一个变量,针对不同的失败将其设置为不同的值:
:Abort
echo The Process is aborting
exit /B %exitCode%然后,可以通过bat文件中的多个goto下令访问该逻辑。
(实际的中止例程将比这个简单的echo下令风趣得多。错误消息可以是多行,并且具有可变的内容,所有内容都写入日记文件和控制台,但我在这里对其进行了简化,以便将重点放在退出下令上。)
总结
在本文中,我详细先容了调用内部例程和其他bat文件的不同方法。您已经学习了如何从这些调用中返回,或者如何简单地从任何地方突然竣事整个过程。您还学习了如何启动或生成另一个bat文件,该文件完全独立于第一个bat文件。最重要的是,您现在了解了goto和call下令之间的重要而玄妙的区别。简而言之,调用返回控制并且可以到达它的bat文件之外,而goto则两者都不做。
这个谜题另有一大块没解开。调用的bat文件可以向被调用的bat文件传递多个参数,而被调用的bat文件甚至可以设置和传递参数作为返回。这比人们想象的要复杂得多,我将在后面文章中详细说明所有的细微差别。
本文由博客一文多发平台 OpenWrite 发布!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]