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 LABEL

goto 命令跳过了中间的 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 LABEL

Before 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命令,但只在不需要返回代码的情况下使用。

在前面的文章中,我们介绍过基本中止逻辑,但将其解释留到后面,也就是现在。

:Abortecho The Process is abortingexit /B 1

这个退出命令的行为与 exit /B 类似,但有一个例外。当控制返回到调用代码的位置时,该选项后面的命令的数字参数变成errorlevel中包含的新值。简而言之,该命令脱离bat文件或例程并返回退出或返回代码。在前面的例子中,返回码是1。但是,如果没有检测到错误,则bat文件的主逻辑可能以将返回代码设置为0结束:exit /B 0

如果检测到致命错误,主线逻辑中的 goto :Abort 命令将把解释器引导到中止逻辑。必须使用 goto 命令,因为 call 命令会将中止逻辑视为被调用的例程;将设置错误级别,但控制权将返回到致命错误的位置。但是当使用goto命令导航到标签时,不会调用例程;它仍然被认为是在主线逻辑中,并且exit命令结束了bat文件,而不是一个例程。

为了更灵活,你可以为退出代码创建一个变量,针对不同的失败将其设置为不同的值:

:Abortecho The Process is abortingexit /B %exitCode%

然后,可以通过bat文件中的多个goto命令访问该逻辑。

(实际的中止例程将比这个简单的echo命令有趣得多。错误消息可以是多行,并且具有可变的内容,所有内容都写入日志文件和控制台,但我在这里对其进行了简化,以便将重点放在退出命令上。)

总结

在本文中,我详细介绍了调用内部例程和其他bat文件的不同方法。您已经学习了如何从这些调用中返回,或者如何简单地从任何地方突然结束整个过程。您还学习了如何启动或生成另一个bat文件,该文件完全独立于第一个bat文件。最重要的是,您现在了解了goto和call命令之间的重要而微妙的区别。简而言之,调用返回控制并且可以到达它的bat文件之外,而goto则两者都不做。

这个谜题还有一大块没解开。调用的bat文件可以向被调用的bat文件传递多个参数,而被调用的bat文件甚至可以设置和传递参数作为返回。这比人们想象的要复杂得多,我将在后面文章中详细说明所有的细微差别。

本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/796432.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pbootcms后台的百度普通收录token怎么填写?怎么获得?

要在PbootCMS后台填写百度普通收录token,你需要先获得这个token,然后按照以下步骤填写到后台: 如何获得百度普通收录token访问百度搜索资源平台打开百度搜索资源平台的网址:https://ziyuan.baidu.com/ 如果你还没有账号,请先注册一个百度账号。添加站点登录后,进入用户中…

PbootCMS实现后台编辑器微信公众号图片本地化

为了实现PbootCMS后台编辑器将微信公众号上的图片本地化,可以按照你提供的方法进行修改。以下是详细的步骤和修改内容: 1. 修改 coreextendueditor/phpction_crawler.php 文件 原始代码/* 抓取远程图片 */ $list = array(); if (isset($_POST[$fieldName])) {$source = $_POS…

市场主体登记

市场主体登记服务 4.0tomcat部署与安装[root@VM-4-9-centos ~]# mkdir /data/soft/ [root@VM-4-9-centos ~]# tar -zxvf apache-tomcat-9.0.68.tar.gz[root@top164 ftpdir]# tar -zxvf apache-tomcat-9.0.68.tar.gz [root@top164 soft]# cp -a cp -a apache-tomcat-9.0.68 apac…

PbootCMS怎么安装?注意事项

安装PbootCMS的过程相对直接,下面是详细的步骤,帮助你完成安装: 1. 下载PbootCMS程序访问PbootCMS官方网站或其他可信来源下载最新版本的程序包。 确保下载适合你服务器环境的版本。2. 上传程序包使用FTP客户端(如FileZilla)或其他方式将程序包上传到你的虚拟主机或服务器…

PbootCMS程序后台登录密码重置工具

如果你忘记了PbootCMS后台的登录密码,可以使用官方提供的密码重置工具来重置密码。以下是使用PbootCMS密码重置工具的步骤: 1. 下载重置工具访问PbootCMS官网或其他可信来源下载密码重置工具。 通常是一个名为 resetpw.php 的文件。2. 上传重置工具将下载好的 resetpw.php 文…

Pbootcms网站忘记后台帐号密码如何重置?

如果你忘记了PbootCMS后台的账号密码,可以按照以下步骤来重置密码: 方法一:使用官方提供的密码重置工具下载重置工具访问PbootCMS官网或其他可信来源下载密码重置工具。 通常是一个名为 resetpw.php 的文件。上传重置工具使用FTP客户端(如FileZilla)将 resetpw.php 文件上…

PbootCMS模板安全设置与加固方法

为了确保PbootCMS模板的安全性和稳定性,可以采取一系列的安全设置与加固措施。下面是一些具体的步骤和建议: 1. 权限设置目录权限:调整关键目录的权限,防止未经授权的写入操作。/apps:禁止写入权限 (chmod 0555) /config:允许读写权限 (chmod 0777) /core:禁止写入权限 …

PbootCms模板搭建网站,可能会遇到内页无法正常访问的情况

当你遇到PbootCMS内页无法正常访问的问题时,关闭伪静态并转为兼容模式是一种简单有效的解决方案。以下是详细的步骤: 步骤详解登录后台管理系统打开你的PbootCMS网站后台管理系统。 使用管理员账号登录。进入设置页面在后台管理系统的左侧导航栏中找到“设置”选项,并点击进…

Go语言SQL操作实战

关注TechLead,复旦博士,分享云服务领域全维度开发技术。拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,复旦机器人智能实验室成员,国家级大学生赛事评审专家,发表多篇SCI核心期刊学术论文,阿里云认证的资深架构师,上亿营收AI产品研发负责人。Go语言凭借其高效…

PbootCMS网站程序提示 执行SQL发生错误!错误:disk I/O error

当PbootCMS网站程序提示“执行SQL发生错误!错误:disk I/O error”时,这通常意味着磁盘出现了读写错误。这种错误可能是由于以下几个原因导致的:磁盘空间不足:这是最常见的原因之一。当服务器的存储空间耗尽时,新数据无法写入磁盘,从而导致I/O错误。文件系统损坏:磁盘上…

好题分享2

好题分享2 K.CF1142D 记 \(f_{i,j}\) 表示前 \(i\) 个字符,所有后缀,排名为 \(j\) 的好串个数。 转移只需要考虑 \(j\bmod 11<str_i\),求出 \(nxt_{j,c}\) 表示排名为 \(j\) 的好串加入字符 \(c\) 后的排名(一定合法)。 发现序列是递增的。本文来自博客园,作者:蒟蒻o…