Windows批处理学习(二)——批处理(2)

时间:2022-01-12 23:06:32

前记

   本篇紧接上一篇继续探索批处理脚本,上一篇主要介绍了批处理所支持的数据类型以及批处理中常见的符号所表示的意义,这一篇则介绍批处理的常见命令语句的使用方式。闲话少说,直入正题。

DOS批处理的使用

   任何程序设计语言除了提供数据类型的支持、特殊符号的操作处理支持,当然还需要提供分支、循环、跳转语句的支持才能算的上是完善的语言。批处理的数据类型和特殊符号在上一篇已经介绍过,下面看看批处理中支持的分支语句、循环语句、跳转语句和其他控制语句。

1.常见内置环境变量

   批处理内置环境变量包括Windows的系统环境变量等,以下只是介绍接个在批处理中常用的批处理环境变量,至于批处理中引用Windows环境变量的用法与引用自身内置变量一样,关于Windows环境变量可以自行查看资料。

1.1.cd——当前工作目录

    “cd”是MS-DOS目录切换的命令,当然它也是MS-DOS提供的内部环境变量,用于引用当前批处理脚本的工作目录完全路径名;其实与无参数的“cd”命令的返回结果一样,当作为环境变量引用的时候比较方便,可以直接使用“%cd%”表示当前工作目录。

1.2.date——当前系统日期

   “date”是MS-DOS提供的日期管理命令,同时也是MS-DOS提供的内部环境变量,用于表示当前系统日期,在Windows中通常与右下角日期格式一致。在批处理中可以直接使用“%date%”获取当前系统日期。

1.3.time——当前系统时间

   “time”是MS-DOS提供的时间管理命令,与“date”命令一样也是MS-DOS的内部环境变量,用于表示当前系统时间,在Windows中通常与右下角时间格式一致。在批处理中可以直接使用“%time%”获取当前系统时间。

1.4.random——0~32767之间的随机数

   “random”是MS-DOS提供的随机数内部环境变量,该变量返回的是一个0~32767之间的随机十进制数值。所以当我们需要使用随机数的时候可以直接使用“%random%”来获取。

1.5.errorlevel——错误级别变量

   “errorlevel”可译为“错误级别”,是MS-DOS(批处理)内置的用于监听某些语句执行成功与否的变量。可以将它看作批处理中某一句代码的返回值,它的结果是一个数值类型的代码,每一个代码都表示一种错误级别;它与每一条语句进行绑定,也就是说每一条语句都会返回一个错误级别代码并赋值给“errorlevel”变量,当然也有例外的情况,除过“pause”,“cls”,“set”,“echo”,“rem”,“path”,“title”等命令语句外大部分的文件和目录处理命令行都会返回错误级别代码。至于哪些语句可以返回、哪些语句不返回可以自己测试看看。

   当某一条语句执行成功时将返回“0”,即“errorlevel”等于“0”时表示语句执行成功;如果执行失败则返回对应的代码,也就是说如果“errorlevel”为非“0”的结果都可以视为上一句代码执行失败。也就是说如果返回了错误级别代码就会直接赋值给“errorlevel”变量,之前的值就被覆盖了,如果没有覆盖就说明该条语句没有返回错误级别代码。

   从上面的介绍可以得知,单单凭借“errorlevel”变量来获取某条语句执行结果是不准确的,因为部分语句是没有错误级别代码返回的,所以我们可以知道当“errorlevel”变量的值不为“0”时就代表某处语句发送了错误。“errorlevel”变量可以与“if”条件语句一起使用来进行判断。

1.6.cmdextversion——命令行版本变量

   “cmdextversion”可译为“CMD扩展版本号”,是MS-DOS提供的命令行扩展版本号常量,它一般与MS-DOS发行版本有关,第一个版本的时候改变量的值为“1”,每次对命令扩展名有相当大的增强时,版本号会增加一个。需要注意的是只有当命令扩展名被启用的时候才存在变量“cmdextversion”。

   常常使用“cmdextversion”来检测命令行环境,例如在第二个版本中新增了一个扩展,则在第一个版本中是无法使用的,需要在执行前检查版本是否为“2”,如果是则可以成功执行,否则无法执行。实质该变量几乎用不到。

1.7.cmdcmdline——命令行执行程序

   “cmdcmdline”可译为“CMD命令行”,是MS-DOS提供的命令处理器命令行引用的常量,它一般返回的是MS-DOS执行解释器的完全路径名。

1.8.path——执行路径

   “path”可以理解为“执行路径”,当指定一个程序名称后会首先在“path”指定的执行路径目录中进行程序搜索,如果搜索到则执行。“path”也可以是一个命令,同时也是一个内置变量,可以通过“%path%”来引用当前批处理程序的执行路径信息,默认为Windows系统环境变量中的“path”变量值。

2.批处理控制语句

2.1.pause——批处理暂停

   “pause”命令用于暂停当前批处理程序的执行,并不是终止,只是暂时的停止执行并可以及时恢复执行过程。我们进程会见到一个批处理执行完成后必须按一下键盘,才能退出批处理程序,这就是使用了“pause”的效果。当执行到“pause”默认的会在批处理控制台显示“请按任意键继续...”字样,当按下任意键时则恢复,继续执行批处理程序。大多数的情况下都会使用到该命令,用法如下:

pause [...]

没有任何参数的“pause”命令的实质就是输出“请按任意键继续...”并监听按键事件触发,当触发按键后则终止暂停。

   默认情况下,批处理文件一次执行完毕后就自动退出,就是我们看到的大多数情况下“一闪而过”的情况,如果我们想在批处理控制台输出什么信息则都无法查阅;现在就可以使用“pause”命令在批处理执行完成退出之前进行批处理程序的暂停操作,则就可以保留MS-DOS解释器的窗口,从而查看MS-DOS的控制台信息。我们来分析一下的代码:

1
2
3
pause
pause > a
pause > nul

保存为“.bat”文件后执行可以看出,第一条语句执行的结果为“请按任意键继续...”并等待按下任意键;第二条语句执行的结果为什么也没有输出,而是在当前工作目录中新建了一个名为“a”的文件,内容是“请按任意键继续...”,同时等待按下任意键;第三条语句执行的结果是没有输出内容和新建“nul”文件并等待按下任意键。来分析一下代码,“>”用于将命令的执行响应信息输出到指定的文件,所以“pause > a”会将“请按任意键继续...”输出到名为“a”的文件中,那么为什么“pause > nul”没有输出到文件呢?

   “nul”是一个特殊的字符串,在批处理中它表示“空字符”,它是一个概念上的空字符,表示没有值,不是我们所说的空白符。上面的例子中的“pause > nul”意思就是说输出空内容,所以即不输出内容,也不输出到文件。也就是说,我们可以使用“pause > nul”来取消“pause”命令的输出内容。

2.2.echo——回显设置

   关于批处理的回显问题,在上一节已经讲到过,“回显”就是打印要执行的命令语句,也就是每执行一条命令语句,都会先打印出来,然后在执行,当然这样查看程序执行过程比较混乱,所以大多数情况下需要关闭回显功能。上一节提到了“@”符号作为命令的前缀用于关闭该命令的回显功能,如果要关闭所有的命令回显功能,则需要在每一个命令前加上“@”符号,比较繁琐,下面就来介绍一种简单的处理方式——“echo”命令语句。

   “echo”命令语句在批处理中,有两个作用:其一就是控制当前批处理程序的回显打开或关闭的状态设置,其二就是在MS-DOS解释器控制台输出信息。第二种作用前面已经用到很多次了,可以自行尝试一下。下面来看看使用方式:

echo [ON | OFF]

echo 信息

echo符号 [ON | OFF | 信息]

   首先来看第一种方式,演变为“echo”、“echo on”或“echo off”三种方式,其中无参数的“echo”命令用于查看当前“echo”状态(即回显状态),默认情况下是开启的;“echo on”命令可以开启回显;“echo off”命令用于关闭回显,“echo off”的关闭可以适用与当前批处理程序,如果没有显示打开,即使用“echo on”命令,则当前批处理的回显状态一直处于关闭状体,所以我们可以使用“echo off”来代替繁琐的“@”命令回显屏蔽符号。例如我们最常用的两种方式:

1
2
echo  off
cls

1
@ echo  off

第一种方式我们调用了“echo off”命令关闭了当前批处理的回显状态,而“echo off”命令在执行前,回显是开启的,所以使用“cls”来清空屏幕内容;第二种发送直接使用“@”符号屏蔽“echo”命令的回显功能;从而达到关闭所有回显状态。关于回显状体的设置,我们通常都在批处理的开头设定,因为这样比较合理,所以建议使用“@echo off”命令。

   再来看第二种方式“echo 信息”,可想而知用于在控制台输出“信息”,其实这个信息就是你要输出的字符串,这种方式比较容易理解。要输出的内容紧接“echo”命令之后,注意必须使用空白符进行分割。我们来看下面的例子

1
2
3
@ echo  off
echo  Hello World!
pause > nul

保存为批处理文件并执行,可以看成在控制台只输出了“Hello World!”信息,没有其他信息,可以看出“@echo off”关闭回显功能已经起效。

   最后看第三种方式“echo符号[信息]”,为什么会多出一个“符号”呢?首先看看我们如何输出“off”和“on”字符,可见使用第二种方式执行后实质就是第一种方式设置回显状态的命令,根本达不到输出“off”或“on”的目的。所以批处理提供了一种特殊的方式来输出像“off”或“on”这样的特殊命令字符,使用“echo+符号+字符”的方式来输出。例如:

1
2
3
4
5
@ echo  off
echo .off
echo .
echo .msg
pause > nul

保存为批处理文件并执行,输出的内容为:

off

(空行)

msg

上面的例子中,我们使用了特殊符号“.”,从例子可以看出无信息的“echo.”表示的是输出一个空白行,有信息的“echo.信息”命令等同于“echo 信息”输出信息用法。

   事实上,批处理输出空白行的方式有多种,都是使用“echo特殊符号”的方式输出。当特殊符号后紧接特殊命令字符的时候,特殊符号用于将特殊命令字符转义为普通字符;当特殊符号后紧接普通字符是直接输出,类是于“echo 普通字符”方式。批处理中对“echo”命令提供的“特殊符号”有数十种,也就是说输出空行的命令有多种方式。其中提供的特殊符号包括“=”、“,”、“;”、“+”、“/”、“[”、“]”、“:”、“.”、“\”,使用“echo”集合任何一种特殊符号都可以输出空白行。

   可以将上面的特殊符号分为三组,第一组有“=”、“,”、“;”,它们默认都是批处理中的特殊分隔符号,其实可以将分隔符看作命令参数或选项的一部分,通常批处理命令在执行带有分隔符的参数是会直接跳过第一个符号,也就是分隔符,而“echo”命令跳过分隔符后其后的字符为“NUL”,所以输出了空行,而当分割符为“空白符”时会跳过并解析其后的字符是否是命令参数;第二组有“+”、“/”、“[”、“]”,它们不是特殊的分隔符,所以会将其作为一个整体进行解析,但是“echo/”等又不是MS-DOS命令,所以会作为外部命令来搜索和执行,它们可以作为外部命令进行执行;第三组有“:”、“.”、“\”,既不是特殊分隔符,也不是外部命令,在执行的过程中,会尝试自动修复命令进行命令的修复转换,所以它们的效率是极低的。(信息来自“批处理技术内幕”介绍)

   通过后面的简单介绍其实为了说明一定,从执行效率上来将,当使用“echo”命令输出空行时可以优选考虑使用“echo=”或“echo,”或“echo;”命令,上面所列车的三组符号中,每组的效率依次递减。

2.3.rem/::——代码注释

   任何一种编程语言,都必须存在注释标识才能让别人读的懂。批处理脚本同样也提供了代码注释功能,主要通过“rem”命令来实现文档注释说明。“rem”命令用于在批处理或“CONFIG.SYS”文件中标注注释信息,用法与“echo”输出命令一样,在命令后标准一段字符串作为注释信息。使用方式如下:

rem 注释说明信息

“注释说明信息”可以是任意文字,也可以是一条命令语句,被注释的语句和文字不参与解释执行。例如:

1
2
3
4
@ echo  off
rem  echo  空行
echo ,
pause > nul

保存并执行的结果为输出一个空行,而“rem”后的“echo”语句并没有执行。

   在批处理中还存在符号“::”与“rem”命令的作用一致,可用于语句的注释说明。用法与“rem”也一样,如下:

::注释说明信息

“::”是一个特殊符号,并发批处理脚本规范的注释命令,在批处理中使用“::”标注的语句或字符串,作为无效信息,在执行过程中将直接忽略;而“rem”标识则会解释为“rem”命令的作用。也就是说在作用上它们是相同的,但是在原理上就不同了。其实“::”用于弥补“rem”命令的某些不足存在的,在某些特殊的情况下,使用“rem”命令注释带有“>”、“<”、“>>”、“|”等特殊符号的时候不能达到预想的效果,但是可以使用“::”来进行注释。

2.4.set——变量管理

   变量,一般的编程语言中都存在这个名称,它表示一个可变的量,可以在程序中寄存一个数据项,并在其他的地方引用。从批处理支持的数据类型来看,批处理脚本中变量的类型应该有字符串和数值两种。讲到变量,就得提提变量的名称了,批处理脚本中对变量的名称没有做任何规定,可以是任意符号或字符串,当然也可以是数值,所以说批处理脚本是比较弱智的。

   批处理中的变量主要使用“set”命令来维护和管理,而在批处理中的变量也称为环境变量。批处理规定的“set”命令用法比较多,主要有以下四种用法。

1.“set”命令查看变量

   “set”命令可以用于查看变量信息,它返回的是所有符合的变量列表,格式为“变量名=值”。用法比较简单,如下:

set [变量名前缀]

这里“变量名前缀”的意思是指“set”命令会在所有变量中进行查找,如果某个变量名的前缀(从第一个字符开始到第N个字符)与所给定的变量字符串相匹配则将改变了视为要查找的变量,是一种前缀查找方式。当没有指定任何变量前缀时则列出所有的变量列表。

2.“set”命令管理字符串变量

   “set”命令可以实现字符串变量的定义和删除等操作。用法比较简单,如下:

set 变量名=[值]

这里使用了一个“=”紧跟在变量名称后,表示定义一个变量并进行赋值,这里如果把“=”省略了则变为查看变量命令了。因此当需要定义变量的时候不可缺少“=”,“值”是可选项,当存在时则表示给当前变量赋值;如果不存在则表示删除当前变量,也就似乎给变量赋空值。可以参考下面的例子:

1
2
3
4
5
6
@ echo  off
set  var=abc
echo  var=%var%
set  var=
echo  var=%var%
pause > nul

保存为批处理文件并执行,输出的内容为:

var=abc

var=

当给指定变量赋空值时表示移除该变量。

3.“set”命令管理数值变量和运算

   “set”命令不仅可以管理字符串变量,同样可以管理数值类型的变量。批处理中使用“set /a”命令来实现数值的运算操作,“/a”是“set”的一个选项,表示其后的字符将被作为数值和算术操作符进行处理,如果不是数值将提示错误。用法如下:

set /a 数值表达式

这里的“数值表达式”不是一个固定的值,而是一种由数字和符号组成的任何一种算术表达式。表达式可以包含前面介绍的任意一种或多种“数值类型符号”,具体符号可以参考具体说明。例如,“set /a result=123+345”,则表示将“123+345”的计算结果赋值给“result”变量;而“set /a 123+345”在表示计算“123+345”的结果;同时还支持简单的位运算等,支持“()”优选运算,支持“,”多个表达式同时运算等特点。例如:

1
2
3
4
5
6
7
@ echo  off
set  /a  a=1,b=2
set  /a  result=%a%+%b%
set  result1=%a%+%b%
echo  算术运算:%a%+%b%=%result%
echo  字符串:%a%+%b%=%result1%
pause > nul

保存为批处理文件并执行,输出的内容为:

算术运算:1+2=3

字符串:1+2=1+2

从例子可以看出,如果要进行数值运算,必须使用“set”命令的“/a”选项来标明。

4.“set”命令实现控制台输入

   下面来介绍“set”命令的另一个扩展功能,从控制台或其他设备或文件将信息读取一行字符串并赋值给指定的变量。使用“/p”选项来启用这个功能,用到的较多的地方就是读取从控制台输入的字符串。当解释器执行到“set /p”命令时会等待用户的输入完成,一般使用回车键表示输入完成;在输入过程中可以使用“CTRL+C”快捷键强制退出输入状态。用法如下:

set /p 变量名=[值]

只是在定义字符串变量的操作之前加上了“/p”选项,其中“/p”选项表示将启用控制台输入功能,并将输入的内容赋值给“/p”后指定的变量名,注意“=”不能缺少。当然也可以赋给变量初始值,但是当输入完成后变量将被重新赋值。例如:

1
2
3
4
@ echo  off
set  /p  info=请输入内容:
echo  你输入的内容为:%info%
pause > nul

保存为批处理文件后可以自行测试。

2.5.cls——清屏

   “cls”命令,在MS-DOS那一节已经讲过了,主要用于清除当前屏幕(包括当前语句)中的所有显示信息,当感觉屏幕内容较多或较混乱时可以使用,用法比较简单,它没有多余的选项。下面看一个例子,使用“cls”命令清除回显内容实现“@echo off”命令的效果:

1
2
3
4
rem cls清除屏幕内容
echo  cls的使用
cls
pause > nul
2.6.color——批处理显示颜色设置

   “color”语句用于设置当前批处理MS-DOS控制台的前景(显示字体)和背景颜色,可以使用该命令来设置当前会话中别致的命令行窗口。用法如下:

color [前景颜色值[背景颜色值]]

“color”主要用于设置MS-DOS控制台颜色值,MS-DOS系统使用的十六进制的数值来表示16种颜色,数值与颜色描述表如下:

颜色值 颜色描述 颜色值 颜色描述 颜色值 颜色描述
0 黑色 6
黄色
C 淡红色
1 蓝色 7 白色 D 淡紫色
2 绿色 8 灰色 E 淡黄色
3
湖蓝色
9
淡蓝色
F 亮白色
4 红色 A
淡绿色


5 紫色 B

淡浅绿色



   针对“color”语句来说,无参数的“color”语句可以将当前MS-DOS控制点前景和背景颜色还原为默认值,默认前景为白色字体,背景为黑色;对于有参数的“color”语句,第一个颜色值表示前景颜色,第二个颜色值表示背景颜色;如果只有一个值则表示设置前景颜色,也就是显示文本颜色。

   有一点需要注意的是,如果前景和背景颜色值相同时会导致颜色冲突,所以MS-DOS会将“errorlevel”错误级别设置为1,表示设置颜色异常;也即是说MS-DOS不允许前景和背景颜色设置为同一个颜色值。

2.7.title——批处理程序标题设置

   “title”命令语句用于设置当前执行批处理命令提示窗口的窗口标题,和“color”命令差不多都用于设置批处理程序的。当需要自定义命令行窗口标题是可以使用该命令实现。用法比较简单:

title 标题内容

只需要在命令后紧跟标题信息即可。理论上将“title”为设置批处理标题,实际上它用于改变批处理标题,批处理程序默认的标题为当前“cmd.exe”程序的执行路径,当执行到“title XXX”命令时,会将批处理程序运行窗口的标题更改为“XXX”字样信息,如果再执行一次“title aaa”则会修改为“aaa”标题。

2.8.more——分页显示

   “more”命令语句用于分页显示命令语句响应的内容,也就是控制台输出的内容。当某个命令语句的输出信息太多时就比较凌乱,可以使用“more”命令来实现分页输出的效果。之前在介绍“type”命令的时候使用过了“more”语句,当时使用的命令语句是“type a.txt |more”,这只是“more”命令的常见的用法,实质上“more”主要用于查看文件内容。

1.分页查看控制台显示内容

   当一个命令语句的响应信息较多时,可以使用“more”命令来实现分页查看的效果,常使用管道重定向符号“|”将命令行的输出信息作为“more”命令的输入信息进行处理。用法如下:

命令行语句 | more [more命令选项

从用法规则上看,“| more”命令作为某个命令语句的子语句,其中管道重定向符号“|”用于将命令行语句的输出信息作为“more”命令的输入内容进行处理,从而达到对命令行输出信息的分页查看效果。

2.分页查看文本文件内容

   “more”命令不仅可以接收MS-DOS控制台的输出信息,同样可以接收MS-DOS从文件读取的信息,这种用法非常类似“type .. | more”命令查看文件内容的用法。用法如下:

more [more命令选项] [<] [files]

“more”命令可以替换“type”来实现文件内容的友好显示。其中输入重定向符号“<”是可选项,当然为了标准可以明确标识;当要查看的文件未指定时,则接下来的输入信息将作为查看的内容,如果要同时查看多个文件,则文件名需要使用空白符分割,实质是将文件内容拼接后显示的。

   “more”命提供丰富的处理选项,可以通过“more/?”或者“help more”命令来查看,其中“/C”选项可以在显示下一页内容前清除屏幕信息;“/S”选项可以将多个空白行缩为一行进行显示;“/E”选项可以启用“more”名的扩展功能,从而实现对子命令的支持,例如可以通过“S n”子命令来跳过下一页的n行信息等,具体说明可以查看使用说明。

2.9.if——条件判断(分支)语句

   “if”语句是批处理中的条件分支语句,表示的意思就是“如果...则...否则...”,大多用在批处理程序中的条件处理部分。“if”语句在批处理中使用的是比较广泛的,例如要查看某个文件,则首先要确定该文件存在才可以查看,否则MS-DOS会抛出错误信息,这个时候就可以使用“if”语句进行判断。“if”命令语句是通过条件成立与否来决定语句的执行,这里的条件成立和条件不成立可以理解为“true”和“false”,但是批处理中不存在这两个常量。“if”语句所表达的意思是只有当条件成立时才会执行指定的命令语句,主要有以下几种用法。

1.判断信息是否相等(“==”)

   “if”命令语句就是用于条件的判断,然而由于批处理脚本本身比较弱化,所以初始的MS-DOS只能支持信息相等的比较,也就是只支持“==”操作符。用于比较字符串与字符串、变量与变量、变量与字符串之间是否相等,如果相等则表示条件成立。用法如下:

if [not] 信息比较表达式 (

   命令行1

) else (

   命令行2

)

这里的“信息比较表达式”的格式为“字符串1==字符串2”或“变量1==变量2”或“变量==字符串”的形式,也即是说只能使用“==”进行字符串或变量之间的比较,上面的“not”表示相反操作,不做多的解释,来看下面的例子:

1
2
3
4
5
6
7
@ echo  off
if  abc==ABC (
    echo  abc euqal ABC
else  (
    echo  abc not euqal ABC
)
pause>nul

保存为批处理文件,执行既可以看到效果,可以自行修改,添加“not”试试。

2.判断错误级别信息

   错误级别“errorlevel”是MS-DOS的内置环境变量,在上面已经介绍过,主要用于保存上一条命令语句是否执行成功,成功则返回0,失败或错误则返回相对应的错误级别码。然而“errorlevel”是内置环境变量,所以可以使用下面的方式判断:

1
2
3
4
5
6
7
@ echo  off
if  %errorlevel%==0 (
   echo  success!
else  (
   echo  failed!
)
pause>nul

然而“if”语句提供了一种特殊的错误级别判断方式,如下:

if [not] errorlevel number (

   命令行1

) else (

   命令行2

)

这种方式并不是使用变量的方式进行引用,而是作为关键字使用,“number”表示一个错误级别码,“not”表示相反操作,不做多的解释。使用这种方式比较简洁。

3.判断文件是否存在

   在上面已经提到关于文件是否存在的判断,“if”语句提供了一种特殊的文件判断方案,用法如下:

if [not] exist filepath (

   命令行1

) else (

   命令行2

)

其中“exist”是关键字表示“存在”,“filepath”表示要判断的文件路径,如果检查到指定的文件存在则执行对应的命令块,“not”表示相反操作,不做多的解释。多说无益,直接看例子:

1
2
3
4
5
6
7
8
@ echo  off
if  exist C:\a.txt (
   echo  file  is  find !
del C:\a.txt
else  (
   echo  file  is not found!
)
pause>nul

上面的例子表示如果检查到C盘存在“a.txt”文件则删除该文件,保存为批处理文件试试即可。

4.判断MS-DOS扩展版本号(扩展用法)

   MS-DOS扩展版本号“cmdextversion”是MS-DOS的内置环境变量,在上面已经介绍过,当在使用某个新扩展特征时可以首先判断版本号是否对应,不过该用法需要在启用命令扩展之后才能使用,而命令扩展默认是启用的,进行扩展版本号判断是“if”语句的扩展用法。用法如下:

if cmdextversion number (

   命令行1

) else (

   命令行2

)

意思是说当当前批处理扩展版本号与给定的“number”值对应时执行“语句1”否则执行“语句2”,大多数情况下不会使用这个命令语句。

5.判断变量是否存在(扩展用法)

   变量是否存在的检查是“if”语句的扩展用法,用法比较广,可以判断变量是否被声明,然后在斟酌使用,不过该用法需要在启用命令扩展之后才能使用,而命令扩展默认是启用的,用法比较类似文件是否存在的判断用法,如下:

if defined 变量名 (

   命令行1

) else (

   命令行2

)

当变量被声明定义后“defined 变量名”才会成立,否则不会成立,具体实例可以自行编写。

6.信息比较运算(扩展用法)

   上面介绍过“if”默认情况下只支持相等比较运算,然后后续考虑则对“if”语句进行了命令扩展,使其可以支持多种比较运算操作,不过该用法需要在启用命令扩展之后才能使用,而命令扩展默认是启用的。用法与“if”相等比较运算的用法一致,如下:

if [/i] 操作数1 比较运算符 操作数2 (

   命令行1

) else (

   命令行2

)

其中操作数可以是字符串也可以是数值,同时还可以是变量;“/I”选项用于开启比较过程中字符串大小写忽略功能;在命令扩展下支持的比较运算符有:“equ(等于)”、“neq(不等于)”、“lss(小于)”、“leq(小于等于)”、“gtr(大于)”、“geq(大于等于)”六种,其中“lss”、“leq”、“gtr”和“geq”四种比较操作符主要用于对数值进行比较,当参与比较的字符串是字符串时,将被转换为对于的ASCII码进行比较;而“equ”和“neq”既可以比较数值也可以比较字符串。来看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ echo  off
set  var1=123
set  var2=abc
set  var3=12
if  /i  %var2% equ ABC (
   if  %var1% geq %var3% (
     echo  %var1%^>=%var3%
   else  (
     echo  %var1%^<%var3%
   )
else  (
   echo  %var2%不等于ABC
)
pause>nul

上面的例子可以说明“/I”的用法,以及其他命令扩展下的操作符用法,保存为批处理文件即可执行查看效果。

   综上所述,特别提示以上的“if”语句中的“else”子句是可省略的,“else”只是起到多分支的作用,表示当条件不成立时执行的处理过程,不必要时可以去掉。关于“()”表示范围,用于表示多条语句执行的语句块(批处理中的每一条语句都是以换行符作为结束符号的),也就是说当条件成立是会执行“if”后“()”内的所有语句,当只有一条语句需要执行时可以省略“()”,特别需要注意的是省略“()”时,命令和“if”语句必须写在一行,当有“else”子句时必须使用“()”。【小提示:注意“()”与关键字之间的空格】

2.10.setlocal/endlocal——启动/结束延迟环境变量扩展功能

   前面已经介绍过变量的引用原理,就是查找变量名对应的值来替换“%变量名%”字符串,从而达到变量引用的效果,这个过程也称之为变量扩展过程,这种过程可用于处理基础的普通的变量,然而我们来看看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
@ echo  off
set  var=before
if  "%var%"  ==  "before"  (
   set  var=after
   if  "%var%"  ==  "after"  (
     echo  重置var的值成功[var=%var%]
   else  (
     echo  重置var的值失败[var=%var%]
   )
)
echo  var=%var%
pause>nul

按照正常的执行流程可以推断出结果为“重置var的值成功[var=after]”,然而真实执行的结果并不是我们想象的,保存为批处理文件并执行输出的结果为“重置var的值失败[var=before]”。我们来看看为什么为出现这种情况?首先声明了变量var的值为before,紧接着为一个“if”语句,又在“if”语句中对变量var进行重新赋值,然后在进行判断,然而该程序在解释执行的过程中,将“if”语句以及其内的“set”命令和“if”语句作为一整条语句进行解释的,当遇到“%var%”时会自动查找“var”的值替换当前语句,也就是整个外层“if”语句中的所有“%var%”字符串,因此内部的“if”判断条件中的“%var%”被替换成了“before”,所以永远都不会与“after”相等。这就是变量扩展的过程,那么外层“if”语句中的“set var=after”是否执行了呢?答案是肯定的,通过在程序末尾追加“echo var=%var%”可以看出。

   通过上面的例子,可以得出一个结论就是批处理中的默认变量替换过程值针对一整条语句的,也就是说如果一整条语句中某个地方有变量的引用,则将会影响到该条语句中的所有变量引用,同一条语句中的所有变量引用会在同一时刻被替换为该变量对应的值。通俗的说,就是默认情况下,一条语句中的变量的值是固定的。

   针对这个现象,批处理提出了延迟环境变量(简称延迟变量)的概念,主要用于对变量进行扩展,弥补普通变量的应用过程中的不足,通过延迟环境变量可以实现在一整条语句中改变变量的值。也就是说可以通过延迟环境变量概念来实现子句内部的变量声明、定义和赋值等操作。批处理中给出了“setlocal”和“endlocal”命令来实现延迟变量扩展功能的开启和关闭操作,来看看两个命令的用法:

setlocal enableExtensions | disableExtensions

setlocal enableDelayedExpansion | disableDelayedExpansion

endlocal

“setlocal”命令有两种用法,第一种用法用于启动(enableExtensions)或者停用(disableExtensions)命令处理器扩展名功能,这个用法主要用于管理MS-DOS解释器的命令扩展功能,默认是开启的,一般很少用到;第二种用法就是现在介绍的用于启动(enableDelayedExpansion)或者停用(disableDelayedExpansion)延迟环境变量扩展功能,默认是停用的。“endlocal”命令用法比较简单,就一个单一的命令行,该命令行主要用于停用延迟环境变量扩展功能,命令执行后将会还原当前批处理的扩展功能为默认值,所做的环境变量的改动不在局限于当前批处理文件;实质上“endlocal”比较特殊,是可以省略的,也不是一定要与“setlocal”成对出现,当一个或多个“setlocal”没有强制使用“endlocal”时会在批处理文件的末尾自动执行“endlocal”命令来还原初始默认设置。

   当开启延迟环境变量的扩展功能后,对环境变量的修改和引用将会扩展到整个批处理程序中。下面来看看如何使用延迟环境变量的扩展功能?现在使用延迟环境变量扩展功能解决上面遇到的问题,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
@ echo  off
setlocal enableDelayedExpansion
set  var=before
if  "!var!"  ==  "before"  (
   set  var=after
   if  "!var!"  ==  "after"  (
     echo  重置var的值成功[var=!var!]
   else  (
     echo  重置var的值失败[var=!var!]
   )
)
pause>nul

在这段代码中,首先使用“setlocal enableDelayedExpansion”语句启用了延迟环境变量扩展功能,保存为批处理文件并执行的结果则为预想的效果“重置var的值成功[var=after]”,代码中并没有强制使用“endlocal”语句停用延迟环境变量扩展功能,但是MS-DOS解释器会在程序的末尾,也就是“pause>nul”语句之后自动调用“endlocal”命令重置MS-DOS环境默认值。

   但是上面的代码与之前的代码还有一处细小的区别,就是这里使用了“!xxx!”的方式来引用变量。然而为什么要使用这种方式呢?“%xxx%”的方式是否可行?答案可想而知“%xxx%”的方式肯定不可行。之前已经介绍过“%xxx%”方式的变量替换原则,当在一条命令的整体语句中时,如果首次遇到“%xxx%”的字符串,则会自动查找并替换该整条语句中的所有“%xxx%”字符串为指定变量的值;正是这个原因,所以提出了延迟环境变量扩展的概念,延迟环境变量扩展就是为了解决整条语句中所有变量被替换的问题,然而在提出延迟环境变量扩展概念的同时扩展了“!xxx!”的变量引用方式,主要用于区别默认的“%xxx%”变量引用方式,而且“!xxx!”变量引用方式只能在延迟环境变量扩展功能开启的环境中才能被解析。

   来总结以下,关于延迟环境变量扩展的用法,延迟环境变量扩展功能主要用于解决像“if”、“for”以及各种复合语句(使用逻辑运算符拼接的语句)等中,用于在语句内部引用修改后的变量,因为默认情况下语句中的变量是被提前替换的,使用延迟环境变量则可以延迟替换过程到解析到该变量时;使用“setlocal enableDelayedExpansion”语句开启延迟环境变量扩展功能后,只能使用“!xxx!”的方式引用变量,表示该变量将被作为延迟环境变量进行处理,如果使用“%xxx%”方式引用将继续作为普通变量处理;开启延迟环境变量扩展功能后可以在必要的时候强制使用“endlocal”或“setlocal disableExtensions”语句停用该功能,默认在程序结尾自动调用“endlocal”语句进行重置。

2.11.for——循环语句

   对于一门程序语言,单单提供分支语句是不够的,必须还要提供循环语句才能满足重复执行某一项任务的需要。在批处理脚本程序中同样提供了循环语句——“for”语句,主要用于实现重复执行某一项命令,“for”语句设计由衷用于对一组文件中的每一个文件执行某项特定的命令操作,同时也可以扩展为对一个集合中的每一个元素执行某项特定的命令操作。“for”语句主要有一种基本用法和四种扩展用法,下面将一一介绍。

1.循环遍历元素(基本用法)

   批处理中的循环主要用于遍历集合中的元素,语法结构如下:

for %%临时变量名 in (集合列表) do (

   命令行

)

基本结构比较简单,使用“for...in...do”的方式,字面意思就是“把在集合中的所有元素都执行一遍操作”,使用这种方式将一个集合中的所有元素都执行一次相同的命令。

   在循环遍历过程中如何取得每一个元素呢?在批处理中的循环语句中提供了一个临时变量用于保存每一个元素(不区分元素类型),从语法上可以看出“%%临时变量名”就是这个临时变量。这里的临时变量的声明与之前将的环境变量的声明不大一致,环境变量的声明直接使用“xxx”方式,而在“for”语句中的临时变量声明使用“%%xxx”方式。至于为什么这样规定,我也没有搞清楚,之前介绍过“%”有转义的作用,所以这里的第一个“%”可以看作为转义字符,正式的变量名为“%xxx”,或许是为了区分环境变量(语句外定义)或语句内变量。需要注意的是临时变量“%%xxx”中的“xxx”可以是任意字符,而且必须是单个字符,当为英文字母时其名称是区分大小写的,为什么只能为一个字符下面会通过例子介绍到。由于“%%xxx”格式的临时变量保存的是一个元素,所以可以直接在“for”语句内部使用“%%xxx”方式来访问该临时变量,这一点也与环境变量的访问方式不同。

   关于集合列表中的值,可以是任意值,多个值使用英文状态的逗号(“,”)分割开来,而且集合无论有多少值都必须使用“()”括起来,表示一个集合范围。上面说过“for”语句的由衷就是为了遍历一组文件,所以不管集合列表中是什么值,都作为文件名来处理,无论该文件是否存在都会进行遍历,默认情况下只是作为文件名(字符串)进行处理,当然还可以进行更高级的扩展处理。也就是说,事实上看到的字符串,实质是作为文件名进行处理的,所以元素支持通配符“*”和“?”,“*”表示当前工作目录下的所有文件。多说无益,看下面的例子:

1
2
3
4
@ echo  off
rem  for 变量元素例子
for  %%i  in  (1,3,5,7)  do  echo  %%i
pause > nul

上面的例子用于变量所有的元素,其中1,3,5,7将作为文件名进行输出。保存为批处理文件并执行可以看看结果。

1
2
3
4
5
6
@ echo  off
rem  for 混合元素例子
for  %%i  in  (1,*)  do  (
   echo  %%i
)
pause > nul

上面的例子用于变量每一个元素,其中“*”表示当前工作目录下的所有文件,并将文件名打印输出,保存为批处理文件执行即可看到效果。

   上面的两个例子足以说明“for”语句的基本用法,其中如果要重复执行的语句为多条语句时必须使用“()”将多条语句括起来,与“if”基本相识;如果是单条语句可以直接写在“do”后面。

2.循环遍历目录(扩展用法)

   批处理中的“for”语句默认是用于遍历文件列表的,如果想变量一个目录列表又该如何操作?在批处理的“for”语句结构中提供了一个“/D”选项,可以将集合列表中的元素值强制作为目录名称进行处理。语法结构如下:

for /D %%临时变量名 in (集合列表) do (

   命令行

)

该用法只是在基本用法的基础上,多了一个“/D”选项用于修饰临时变量,主要是将临时变量的值进行目录检查,如果是目录则取用,否则则丢弃。看下面的例子,在C盘下的文件夹中存在文件和子文件夹:

1
2
3
4
5
6
7
@ echo  off
cd  C:\ test
echo  文件有:
for  %%f  in  (*)  do  echo  %%f
echo  目录有:
for  /d  %%d  in  (*)  do  echo  %%d
pause > nul

通过上面的代码执行结果的对比可以看出“/d”选项的作用,用于匹配目录名称,忽略文件。

3.循环遍历指定工作目录下的文件或目录(扩展用法)

   在第二个用法的例子中开头有一句“cd C:\test”将当前工作目录切换到C盘的test目录,如果不指定则默认工作目录就是当前批处理所在的目录,这样写虽然很直观当时相对比较麻烦。在批处理的“for”语句中提供一种指定工作目录的方式,使用“/R”进行工作目录的指定,用法如下:

for [/D] /R 工作目录 %%临时变量名 in (集合列表) do (

   命令行

)

该用法是基础用法的扩展用法,可以直接在“for”语句内指定要查找的工作目录,使用“/R 工作目录”的方式指定。指定后将在当前“工作目录”中进行文件的查找遍历。当然可以与“/D”一起使用,用于查找变量目录,当与“/D”一起使用时“/D”修饰必须写在“/R 工作目录”的前面。下面我们来改写第二个用法中的例子,如下:

1
2
3
4
5
6
@ echo  off
echo  文件有:
for  /r  C:\ test  %%f  in  (*)  do  echo  %%f
echo  目录有:
for  /d  /r  C:\ test  %%d  in  (*)  do  echo  %%d
pause > nul

保存为批处理文件并执行则可以看到执行结果与第二个用法的基本一致,只不过这个用法输出的是文件或目录的完全路径名称,这是“/R”选项的另一个特点。如果你细心,还会发现“/R”选项还可以查找变量到目录下的子目录或子文件,如果我们在C:\test目录下的某一个目录下再添加一个文件或目录,则同样会打印输出。

   来总结一下“/R 工作目录”的用法,可以查找当前工作目录下的所有文件或目录,包括子目录下的文件或目录,直到没有下一层为止;每一个临时变量保存的是文件或目录的完全路径名称。也就是说使用这种方式我们可以实现目录结构树图,可以自行尝试一下。再来看看上面讲到的两种用法,基础用法和“/D”选项用法只能查找当前工作目录下的文件或目录,而并不能进一步深入查找下一层文件或目录。

4.固定频率循环(扩展用法)

   上面介绍的“for”语句主要用于文件管理中的循环遍历操作,这些循环操作执行的次数都是受到工作目录中文件或目录的数量的影响,是不固定的;当我们需要执行规定次数的某一个操作时,又该如何实现呢?当我们要迭加一个数值又该如何实现呢?其实在批处理的“for”语句中提供了“/L”选项,专门用于实现数值范围的遍历操作,用法如下:

for /L %%临时变量名 in (start,step,end) do (

   命令行

)

从语法结构上看,添加了一个“/L”选项修饰操作,同时“集合列表”也固定了结构,是一个有start、step、end三个数值组成的列表,从语义上可以知道集合列表中的“start”表示循环的开始数值,“end”表示循环的结束数值,而“step”表示循环的递增频率数值;过程是第一次循环临时变量将被赋值为“start”指定的数值,之后每一次临时变量在原有值的基础上增加“step”指定的数值,然后与“end”指定的值进行比较是否小于等于,如果是则执行下一次循环,否则跳出循环。举个例子,如果我们要循环3次则列表集合可以写作“(1,1,3)”,就是说临时变量从1开始,到3结束,每一次循环后增加1;如果要打印输出10以内的奇数,则可以写作“(1,2,10)”。多说无益,来看下面的例子:

1
2
3
4
5
6
@ echo  off
echo  10以内的奇数:
for  /l  %%i  in  (1,2,10)  do  echo  %%i
echo  10以内的偶数:
for  /l  %%j  in  (10,-2,1)  do  echo  %%j
pause > nul

保存为批处理并执行既可以看到结果。“for”语句使用“/L”选项后,要求集合列表必须包含3个数值,其中第一个表示循环起始值,第二个表示循环频率值,第三个表示循环结束值,这些值必须是数值,而且可以为正负数值。

5.高级扩展应用

   上面已经介绍了“for”循环的几种不同应用方式,但是不足以灵活多变,所以批处理还提供了高级扩展应用,包括文件内容循环遍历、内容查找处理操作、动态执行命令行等功能。高级扩展应用使用“/F”选项进行开启,用法如下:

for /F [操作选项] %%临时变量名 in (集合列表) do (

   命令行

)

扩展用法与上面介绍的几种基本一致,不过这里在“/F”选项后包括一个“操作选项集合”,下面会介绍到。

   首先来看看“集合列表”,集合列表可以是文件集合、字符串集合(我们知道文件都是扩展名的,或许可以简单的区分为文件名或字符串)或命令集合。当集合中的元素为一个或多个文件时,则在进入循环语句时,当前文件和之前已经遍历的文件都将处于打开状态,并接受读取等操作,处理包括读取文件行(将文件内容以换行符分割或空白符截断)并将每一行信息解析为一个或多个字符串(按操作语句指定进行解析分割),当为文件名时需要注意的是当文件名中有空格符号是需要使用“""”将文件名引用起来;当集合为一个或多个字符串时,必须使用“""”将字符串引用起来,则执行过程将会对每一个字符串进行一一处理;当集合类型为一个命令行语句时,命令行语句需要使用“''”括起来,则会对该命令行的响应输出信息进行处理。例如:

1
2
3
4
5
6
@ echo  off
for  /f  %%i  in  ( 'echo HelloWorld!' do  (
   set  myvar=%%i
)
echo  myvar=%myvar%
pause > nul

这个例子就是变量“echo HelloWorld!”命令语句的输出信息。

   下面再来看看“操作选项”,这里的操作选项必须使用“""”括起来,可以包含一个处理选项或多个处理选项,多个处理选项之间使用空格符号进行分开,处理选项在该用法中是可选的。如果处理选项不存在,则临时变量表示的是每一个文件或字符串或命令输出的一行内容,这一行内容以空白符进行截断;如果处理选项存在,则临时变量表示的是每一个文件或字符串或命令输出的一行内容中符号条件的部分内容。处理选项包括一下几种(是一种子命令的方式):

选项表达式 说明 举例
eol=c 指定忽略以“c”指定的字符开头的元素,只能是单个字符(如果集合为文件则指忽略以“c”开头的行) eol=a(忽略a开头的行)
skip=n 指定忽略的元素数n,以第一个元素开始,只能为正整数(如果集合为文件则指跳过0-n行) skip=3(忽略前3行)
delims=xxx 指定以“xxx”作为元素的界定符号,默认以空格符或换行符作为元素界定符号。可以包括多个字符,某一元素从第一个字符开始算起包含其中的某一个字符则视为终止,其后的字符将被忽略(如果集合为文件则指以“xxx”作为行的界定符号) delims=。(使用“。”作为换行符)
tokens=x,y,m-n 表示取到每一个元素的第x字符赋值给临时变量,取第y个字符赋值给当前临时变量字母的下一个字母变量,取第m到n个字符组成的字符串赋值给下一个字母变量,一共可以有26个取值。可以使用通配符,*表示所有,?表示单个任意字符 tokens=2表示取每一行的第二个字符;2,3表示取每一行的第二个和第三个字符;2-8表示取每一行第二个到第八个字符组成的字符串
usebackq 用于标记引号("")或('')中的为文件名或命令行 usebackq

上面列表所列的是“/F”选项下的所有操作选项说明,这些选项只有在“/F”选项下才可以使用。废话不多说了,看下面的例子:

1
2
3
@ echo  off
for  /f  "delims=."  %%i  in  ( "a.txt" do  echo  %%i
pause > nul

这段代码是将“a.txt”元素作为字符串进行处理,截取“.”之前的字符并打印,保存为批处理文件并执行即可看到效果。如果我也要将“a.txt”作为文件名则可以在操作选项中加入“usebackq”选项。

   “for”语句的“/F”选项扩展主要用于内容的循环查找操作,在查找过程中对应的临时变量的操作存在一个特殊的扩展处理方式——自动变量扩展,比如说当使用tokens操作选项来取得每一个元素或每一行的某个或几个字符时,可以自动以当前定义临时变量名(单独字母字符)为起点进行后续扩充,定义的临时变量保存取得的第一类字符信息,下一个字符扩展的临时变量则表示第二类字符信息,依次类推,规定最多只能扩充26个临时变量(包括当前变量在内),是由于tokens选项最多只能指定26个值集合。来看下面的例子:

1
2
3
4
5
6
@ echo  off
cd  C:\ test
for  /f  "skip=2 tokens=2,3* delims= "  %%a  in  ( 'dir' do  (
   echo  %%a--%%b--%%c
)
pause>nul

这个例子是将“DIR”命令的输出信息作为遍历内容,首先跳过前两行,然后从第三个字符块开始取值,使用默认的方式进行换行或截断操作,其中第二个字符块将作为“%%a”的值,第三个字节块作为“%%b”的值,第三个之后的字节块作为“%%c”的值。(目前我还没找到什么特殊的规律,这个值只能靠查看结果才能知道所表示的内容是什么,临时变量扩展虽然很方便但是使用需要谨慎,如果没有取到值则会输出“%变量名”信息,我并没有很深入的去了解它,如果你有兴趣,可以深入了解并整理一下结论和规律分享给大家)

2.12.goto/:——跳转语句

   “goto”从字面上理解就是跳转的意思,“goto”语句就是批处理中提供的流程跳转语句,何为流程跳转?首先批处理的执行过程是自上而下顺序执行的,默认情况下,批处理文件中的所有语句都会执行,不论上一条语句是否执行成功。如果在执行过程中遇到某种情况需要进行特殊处理,那么就需要改变执行的流程,不过可以使用“if”语句来实现流程的控制,从理论上也可以实现跳过部分语句代码的过程,但是比较麻烦,需要使用“if”语句块来实现,所以批处理提供了“goto”语句来实现标签式流程跳转。标签式跳转也就是说首先要定义一个标记,然后使用“goto 标签”的方式跳转到指定的标签语句块内,所以“goto”语句必须结合标签实现执行流程的跳转,在批处理中使用“:”来声明标签,来看标签和“goto”语句的基本用法:

goto [:]标签名


: 标签名

 命令行

批处理中规定,“goto”语句用于标签式跳转,其后紧接要跳转到的标签名称(中间使用空白符分割);标签的声明必须使用“:”作为前缀,也就是说在批处理中以“:”开头的字符串或语句都是标签,其标签后的命令行语句是该标签的标签体,只要没有遇到“goto”跳转语句则其后的语句都会执行;其实标签体是一个模糊的概念,很多情况下它是混淆的。看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
@ echo  off
echo  准备跳转到a标签
goto a
echo  跳转到a标签后的语句
:a
echo  已经进入a标签
:b
echo  已经进入b标签
goto end
:end
echo  已经进入eof标签
pause

上面的例子,从语法上看,定义有“a”标签、“b”标签和“end”标签,从执行流程上看,“a”标签和“b”标签是混淆的,因为缺少标签结束语句,所以在使用标签跳转的时候一定要为标签体定义一个“goto”语句,表示跳出标签体,如果是最后一个标签则可以忽略。

   使用“goto”必须注意,标签体在必要的时候必须使用“goto”跳转语句进行终结,否则其后的所有标签或非标签都会作为当前标签的标签体进行执行,正如上例一样;其次还需要注意标签结束时的“goto”跳转语句,如果没有需要,最好不要跳转到当前标签,否则会构成“死循环”,不断的执行当前代码体,理论上是无法退出的。看先一个的例子:

1
2
3
4
5
@ echo  off
:start
echo  an infinite loop
goto start
pause

从执行流程上分析,这段代码首先进入“start”标签,然后跳转到“start”标签,然后在进入“start”标签……从而构成了一个“封闭的回路”,会无穷的执行下去(这只是理论上的猜想,实际上当达到某一个次数后会自动停止)。因此没有必要这种写法是不可取的。最后,再来看一个例子,使用“if”和“goto”实现的简单计算器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@ echo  off
rem goto 语句练习,根据输入内容跳转到不同的标记位置
:start
set  /p  num1=输入第一个数:
set  /p  num2=输入第二个数:
set  /p  op =选择操作符:1.加法 2.减法 3.乘法 4.除法
if  % op % == 1 goto add
if  % op % == 2 goto sub
if  % op % == 3 goto mul
if  % op % == 4 goto div
if  % op % ==  ""  goto :eof
:add
set  /a  result=%num1%+%num2%
echo  %num1%+%num2%=%result%
goto end
:sub
set  /a  result=%num1%-%num2%
echo  %num1%-%num2%=%result%
goto end
:mul
set  /a  result=%num1%*%num2%
echo  %num1%*%num2%=%result%
goto end
:div
set  /a  result=%num1%/%num2%
echo  %num1%/%num2%=%result%
goto end
:end
set  /p  choose=是否退出? (Y /N ):
if  /i  %choose% equ y (
   exit
else  (
   goto start
)

   上面的例子中使用了一个“goto :eof”语句,从运行的流程上看,如果没有选择则会跳转到“eof”标签,从结果上看,实质是退出了批处理文件,为什么呢?因为“eof”标签是批处理中的默认标签,用于跳转到批处理文件的末尾,也就是最后一条语句的后,所以会直接退出批处理文件。这个地方不能直接使用“goto eof”,因为这样会默认将“eof”作为自定义标签进行处理,只能使用“goto :eof”方式。

2.13.start——批处理启动

“start”的字面意思是“启动”,无可异议在批处理中是用于启动程序的。“start”命令比较独特,可以启动人任意的程序或文件,只需要指定程序或文件的名称即可,可以是全名称(如果不指定扩展名会按照环境变量自行查找匹配),执行跨磁盘的程序启动。其实“start”命令是一个启动程序的入口,用法如下:

start ["title"] [/I] [/MIN] [/MAX] [/B] [command/program] [parameters]

其实“start”命令提供的选项操作比较多,可以通过“start/?”或“help start”命令查看,上面列出的是几个常见的选项操作。其中“command/program”表示命令或程序名称,“parameters”表示参数。

   “start”命令主要用于启动批处理程序,可以启动当前批处理程序外的其他批处理文件,例如使用“start C:\test.bat”可以启动C盘下的test.bat批处理程序并在新的MS-DOS解释器中执行,通俗一点的说就是在一个新窗口中打开并执行test.bat批处理程序。实质上“start”命令是以批处理文件默认关联程序打开指定的文件,当然可以使用“title”选项来指定新窗口的标题,使用“/i”选项强制去掉引用旧窗口的环境变量,使用“/min”或“/max”选项指定新窗口是否最小化或最大化,使用“/b”选项强制进行窗口合并等,更多选项说明可以自行查阅。

   同时“start”命令还可以启动其它程序,包括可执行程序以及文件等,但是可能不会提供更多的选项操作。同样的道理,“start”命令是以要打开的程序所关联的默认执行程序打开当前程序或文件的。了解Windows系统应该知道文件关联选项中的一些设置,其实文件都是通过命令语句打开的。

2.14.call——批处理调用

   “call”的字面意思是“调用”,在批处理中“call”命令用于实现批处理文件的调用操作,事实上它不仅能实现批处理文件的调用,还可以实现标签式调用,标签式调用与“goto”的用法非常相识。“call”命令的用法如下:

call 批处理文件路径 | :标签名 [参数]

“call”命令可以在当前批处理文件中调动另一个批处理文件,也可以在当前批处理文件中调用某个声明式标签,从作用可以知道“call”共兼了“start”和“goto”的作用,其实还是存在一定的区别的。

   首先来介绍一下“call”命令调用批处理程序文件,使用“call”语句调用批处理程序与“start”命令启动批处理程序非常类似,只需要指定批处理文件完全逻辑名称或相对路径名称即可,例如“call test.bat”语句既可以执行test.bat批处理文件。细心的你可以会发现执行的批处理文件并不会开启新的解释执行窗口,然后会将被调用的批处理的所有输出显示语句都打印在当前窗口,换句话说就是被调用的批处理程序继承了当前批处理程序的执行环境,然后先退出被调用的批处理程序,最后在退出当前批处理程序,这就是“call”语句与“start”命令的最大区别,“call”的这个功能很类是“start /b”命令,还一个区别是“call”命令没有提供跟多的操作选项,但是可以在“call”语句后面拼接执行新程序时需要的参数(多个参数使用空白分割)。可以看下面的例子:

1
2
3
@ echo  off
call  test .bat  test
pause

其中“test.bat”的内容如下:

1
2
3
@ echo  off
echo  %0----%1
pause > nul

从这个简单的例子可以看成“call”命令的执行过程。其次“call”命令也具有调用其他可执行程序功能,与“start”命令使用一样。

   下面看一下“call”命令标签跳转用法,使用“call”语句实现标签跳转语句与“goto”语句的用法非常类似,只需要在“call”命令后紧接要跳转的标签名称即可,唯一不同的是这里的标签名称需要指定“:”前缀,同样可以在标签名称后拼接多个执行参数,看下面的例子:

1
2
3
4
5
6
7
8
@ echo  off
call :lable aaa  "b b"
pause
:lable
echo  firstParam=%0
echo  secondParam=%1
echo  thirdParam=%2
pause

这个例子可以说明“call”语句不仅能实现“goto”语句的功能,同时还可以传递参数。实际上“call”命令调用预先定义的标签时,会将标签语句视为一个批处理程序集进行执行,执行完该标签的所有语句后会再次返回到“call”语句后继续执行,这也是“call”标签跳转与“goto”标签跳转的另一个区别,“goto”标签跳转后会继续向标签后执行,不会自动返回到“goto”语句后。通常情况下,使用“call”命令来调用标签语句时,标签体的末尾应该使用一个“goto :eof”语句来结束标签体,当然也可以使用其他的语句,这样做是为了可以编写多个“call”调用的标签体语句,避免混淆。

   其次来看看关于“call”语句传递参数后如何访问,在之前介绍“%”的时候介绍过“%num”(0=<num<=9)方式可以用来引用某些特殊命令语句传入的参数,其中“num”表示参数的索引,从“0”开始,所以上面我们使用“%0”、“%1”、“%2”的方式来引用“call”传递的参数信息。(后面会继续介绍)

2.15.cmd——启动MS-DOS新窗口

   “cmd”命令,我想学过电脑的人应该都知道,“cmd”实质是“command(命令)”的缩写,用于启动一个MS-DOS命令行解释器窗口,准确的说是启动一个MS-DOS(cmd.exe应用程序)的一个新实例。我们大多数是在运行窗口“cmd”命令来启动一个命令行窗口,其实“cmd”命令还提供了很多操作选项用来设置当前MS-DOS解释器的环境变量。例如可以使用“/T:fg”设置当前命令行的前景(“f”)/背景(“g”)颜色(颜色值请参考“color”命令);使用“/E:ON”(“/X”)或者“/E:OFF”(“/Y”)启用或停用命令扩展功能,默认情况下是启动的;可以使用“/V:ON”或“/V:OFF”启动或停用延迟环境变量扩展功能,用“setlocal”具有一样的作用。而且“cmd”命令还可以将一句字符串作为命令行语句进行解释执行,用法如下:

cmd /S | /C | /K 字符串

其中字符串必须使用“""”引用,“/S”选项用于保留字符串的“""”并进行执行;“/C”或“/K”选项用于将“""”内部的字符串作为命令语句进行解释执行。需要注意的是“/S”选项不能与“/C”或“/K”选项一起使用,而且如果字符串语句是多条命令语句需要使用“&&”符号进行分割。

2.16.path——执行环境路径管理

   “path”是Windows中比较重要的一个东西,在MS-DOS系统中同样提供了“path”命令来定义当前批处理程序的资源路径信息。当需要在批处理程序中调用某一个文件是必须先进入该文件所在的目录,然后才能使用该资源;如果要引用另一个资源必须首选进入其所在的目录(当然你也可以使用完全绝对路径引用),显然这种模式比较笨拙,我们可以首选使用“path”命令指定当前批处理工作所需的所有目录,然后就可以在程序中直接引用资源名称了,既可以减少相应的代码量,也可以是程序更美观。“path”命令的用法如下:

path 目录完全路径[;...][;%PATH%]

path [;]

使用“path”命令可以可以查看当前批处理程序或MS-DOS解释器的执行目录路径;使用“path ;”命令可以将当前执行路径置为空;使用“path dirs”可以设置当前执行路径,其中“dirs”可以为一个目录,也可以为多个目录,多个目录需要使用“;”分割,同时还可以在原有的执行路径上进行路径扩展,可以使用内置环境变量“%path%”来引用原有目录。

   “path”命令设置后,当程序中某个地方引用到某个资源名称,则会在“path”指定的工作目录中进行资源的查找,如果查找到了则引用,否则会导致错误。

2.17.exit——退出MS-DOS

   “exit”命令在之前已经介绍过,这里在作一个简单的补充说明。“exit”命令在MS-DOS解释器用于退出当前“cmd.exe”程序,在批处理文件中用于退出并结束当前批处理程序,同时还可以扩展为结束某个进程。用法格式为:

exit [/B] [exitCode]

无参数的“exit”命令用于退出并结束当前命令行程序;“/B”选项用于强制指定当前退出的是批处理脚本程序而不是“cmd.exe”程序,如果在批处理教程外使用则用于退出“cmd.exe”程序;“exitCode”是一个代码信息,不能与“/B”选项一起使用,代码表示要退出的进程的ID值。

后记

   本篇主要介绍了批处理程序中的内置环境变量,流程控制语句等批处理中常见的命令,包括“IF”、“FOR”、“GOTO”等语句,当然还有其他的不怎么常用的语句和命令等待着大家自行去发掘。介绍的内容可能并不一定全面,希望能谅解。

   梳理知识,分享大家,互利你我!怕拍板砖,就不知道自己整理的对知识掌握的问题所在,找到问题才有所进步,欢迎大家踊跃的拍砖...

本文出自 “阿酷呆” 博客,请务必保留此出处http://akudy.blog.51cto.com/2277883/1257596