zoukankan      html  css  js  c++  java
  • Windows批处理学习(二)——批处理(3)

    前记

       前面介绍过批处理程序中的数据类型、操作符号、内置环境变量和常用的命令语句,这些都是学习批处理的基本知识,需要学习批处理这些知识必须了解到位。

       学习某种语言的最终目的是能够读懂其他人编写的程序代码,用于解决自己的在日常生活或工作中的一些问题,然而前面介绍的基础知识就不能定能够满足这种目的了,所以下面来扩展一下其他常见的知识,总结一下之前介绍的知识,同时通过几个常用的案例来分析一下如何编写批处理脚本。

    DOS批处理的变量扩展

       变量是批处理中的基础内容,常称之为“系统环境变量”。之前介绍了两种访问变量的方式“%变量名%”和“!变量名!”,其中前者是对普通变量的引用,后者是对延迟环境变量下的变量的引用,延迟环境变量大多用在复合式语句中,例如“for”、“if”等语句中。

    1.参数化变量扩展

       之前在介绍“call”命令的时候,介绍过参数的取值方式——使用“%number”,其中number必须是数值,而且值大于等于0小于等于9。下面来看之前的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    @echo off
    set var=test
    call :deal %var% demo
    :deal
    echo %%0=%0
    echo %%1=%1
    echo %%2=%2
    pause

    将上面的代码保存批处理文件并执行,可以看到结果为:

    %0=:deal

    %1=test

    %2=demo

    请按任意键继续. . .

    %0="C: est.bat"

    %1=

    %2=

    请按任意键继续. . .

    首先来看看为什么为执行两次,“call”命令的执行流程不同于“goto”语句,当执行完对应的标签体后会再次回到当前“call”语句之后继续执行之后的程序,所以会执行两次。再来看看取值,“%%0”表示一个转义用于打印输出“%0”字样,当解释器执行到“call :deal %var% demo”语句时会跳转到“:deal”标签体并执行,可以通过“%0”等字样取到“call”命令语句后的参数,所以会打印出“:deal test demo”信息;然后再次进入“:deal”标签体,但是你会看到这次并没有取到参数值,为什么?因为这里是正常的批处理执行语句,并不是“call”语句的调用,但是可以看到“%0”取到的值为当前批处理脚本程序的完全路径名,这就是要提到的第二种参数化变量的扩展作用。

       在批处理脚本中,默认情况下,可以使用“%0”来获取当前执行的批处理脚本程序本身,用于引用当前程序的完全路径名,这是MS-DOS解释器的扩展特点;而在特殊情况下,在取某些特殊命令语句的参数时,“%0”表示命令语句后的第一个参数值,而通常把这一个参数称为批处理标签本身,也就相当于把它视为批处理本身一样,“%1”、“%2”...“%9”等视为对正式参数的引用,所以从这个角度来理解,真正的参数索引应该是“1-9”。

       在Windows系统中,我们可能看到将一个文件拖放到一个应用程序上,则可以使用当前应用程序打开当前文件的情况,那么在批处理中可不可以实现呢?答案是肯定的。来分析一下,该如何实现?如果要打开一个文件必须要指定该文件的路径地址才能打开,接下来的为题就是如何在批处理中获取拖放进来的文件地址。来看下面的例子:

    1
    2
    3
    4
    @echo off
    set /p inPath=请输入或拖放目录和文件...
    echo 你输入的路径为:%inPath%
    pause

    这段代码中“inPath”变量用于获取用户输入的信息,可以输入,同样可以直接将目标目录或文件拖进当前解释器命令行,则可以立即获取当前文件或目录的地址。可以看成这是一种获取方式,但是这种拖放方式必须要在打开批处理执行解释器的情况下才可以使用。下面来看另一种方式,通过参数获取方式,先看例子:

    1
    2
    3
    4
    @echo off
    echo 当前执行程序:%0
    echo 拖拽的文件或目录:%1
    pause

    将这段代码保存为批处理文件,然后将任意一个文件或目录拖放到当前批处理文件上,看看效果。惊讶的是可以看到,“%1”这个变量参数输入的信息就是我们想要的目标文件或目录的完全路径,而“%0”还是当前文件完全路径。上面介绍了“%0”表示的是当前执行程序本身完全路径,而这里的“%1”用于表示目标文件或目录的完全路径地址,这是变量参数的需要注意的另一个特点,“%1”在某些特殊的情况下才能发挥这种引用效果。

       总结一下,在批处理脚本中的“%0”表示当前批处理程序本身的完全路径名,“%1”—“%9”表示对命令参数的引用,而这些参数应用最常见的就是“call”命令。需要注意的是“%1”在某些特殊情况下有另一种作用就是表示要执行的目标程序的完全路径,而这种用法大多是在拖拽文件的时候使用。

    2.单字符变量扩展

       之前在“for”语句中提到了一种变量的扩展方式,非常类似上面提到的参数化变量扩展,然而在“for”语句中的变量名称只能为单个字母,所以可以与参数化变量区分开来。上面提到了“%0”参数可以表示当前程序的完全路径名,那么如何取到当前程序的工作目录呢?截取字符串,这是一个笨拙的方式,在批处理中提供了一种非常简单的处理方式——通过变量扩展来获取。

       下面来看看批处理中定义的变量扩展方式,如下表:

    变量替换方式 说明
    %~变量名 删除变量所表示的值的两端的引号
    %~f变量名 在变量之前追加当前执行路径(目录路径)
    %~d变量名 将变量转换为当前盘符
    %~p变量名 将变量转换为目录路径(不包含盘符)
    %~n变量名 将变量转换为文件名(当集合类型为字符串时)
    %~x变量名 将变量转换为文件扩展名,只适合字符串
    %~s变量名 在变量之前追加当前执行短路径(目录短路径)
    %~a变量名 将变量转换为文件的属性,只适合字符串
    %~t变量名 将变量转换为文件的修改日期,只适合字符串
    %~z变量名 将变量转换为文件的大小(KB),只适合字符串
    %~$PATH:变量名 将变量转换为环境变量的目录
    %~dp变量名 将变量转换为当前执行目录路径
    %~nx变量名 将变量转换为文件全名称(包括扩展名)
    %~fs变量名 将变量转换为完整的短路径名称
    %~dp$PATH:变量名 将变量转换为环境变量的目录
    %~ftza变量名 将变量转换为包含属性、修改日期、大小、全路径的列表

    来看下面的例子,在“%0”参数变量上进行扩展:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @echo off
    echo 正在运行的这个批处理:
    echo 完全路径:%0
    echo 去掉引号:%~0
    echo 所在分区:%~d0
    echo 所处路径:%~p0
    echo 文件名:%~n0
    echo 扩展名:%~x0
    echo 文件属性:%~a0
    echo 修改时间:%~t0
    echo 文件大小:%~z0
    pause

    保存为批处理文件并执行既可以看到不同的效果。

       其实,变量的扩展不仅用于“%0”参数,还可以应用到所有的变量上,包括“for”循环语句中的临时变量,但是大多数情况下用在“for”循环的临时变量上。经过测试这种单字符变量扩展的方式只能用于临时变量或参数变量的扩展上。

    3.字符串变量扩展

    3.1.字符串的拼接

       之前介绍过变量,在批处理中默认的变量都是字符串变量。如何实现在字符串变量值上追加字符串呢?如何实现字符串的拼接呢?下面就来讲讲这方面的例子,首先定义一个字符串变量,我们知道需要使用“%变量名%”的方式引用变量,如何将另一个变量的值追加到当前变量中呢?来看下面的例子:

    1
    2
    3
    4
    5
    6
    7
    @echo off
    set var1=伟大的中国!
    set var2=我为你自豪!
    echo 拼接字符串:%var1%%var2%
    set var3=%var1%%var2%
    echo %var3%
    pause

    从例子可以得出,批处理中的字符串拼接处理非常简单,不需要任何操作符号进行连接。为什么会这么处理?因为批处理中的变量引用方式实质是字符串的替换方案,之前也将过,当解释器执行到“%xxx%”字样的字符串时,会查找“xxx”所表示的变量值并替换当前语句中的所有的“%xxx%”字符串为指定的值,所以不需要任何符号干预;在开启延迟环境变量扩展功能的环境下,当解释器执行到“!xxx!”字样的字符串时,会查找“xxx”所表示的变量值并替换当前“!xxx!”字符串,并不会替换其他地方,这也是延迟环境变量和普通变量的一个最大区别。

    3.2.字符串的替换

       字符串替换是比较常用的操作,批处理中的字符串替换需要依赖变量的扩展功能来实现,使用“:”进行字符串的替换操作扩展。用法如下:

    %str:substr=value%

    其中“str”表示字符串变量名称,“substr”表示字符串变量对应的值中的一个子字符串,“value”表示要将子字符串替换成的新的字符串值。意义就是将原字符串中的某一部分字符(串)替换为指定的内容。来看看下面的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @echo off
    set var=Hello World .
    echo 原字符串:%var%
    echo 将World替换为Tom:%var:World=Tom%
    set /p name=你输入你的名字:
    echo 将World替换为输入的名字:%var:World=%%name%%
    setlocal enabledelayedexpansion
    echo 将World替换为输入的名字:%var:World=!name!%
    pause

    保存为批处理文件并执行可以看到效果,需要提到的是要替换的值是变量,则需要开启延迟环境变量扩展功能并使用“!xxx!”方式来引用该变量值,通过上面最后两条“echo”命令可以看成区别。

    3.3.字符串的截取

       字符串截取也是比较常用的操作,批处理中的字符串截取同样需要依赖变量的扩展功能来实现,扩展用法与字符串替换有点类似,不过这个地方的扩展是基于数值进行字符串截取的。用法如下:

    %var:~m[,n]%

    其中“var”表示变量名称,“m”表示要截取字符串的开始位置索引数值,“n”表示要截取的字符的数量;字符串中的索引是从“0”开始的,也就是说字符串的第一个字符的索引为0,第二个字符索引为1,依次类推。如果只指定“m”的值则表示从第“m+1”个字符开始截取,直到字符串的末尾;如果同时指定“n”的值则表示从第“m+1”个字符开始截取“n”个字符。来看下面的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @echo off
    set var=abcdefgh
    echo 原始字符串:%var%
    echo 字符串索引:01234567
    echo 从第3个字符开始截取:%var:~2%
    echo 截取前5个字符:%var:~0,5%
    echo 截取3-6个字符:%var:~2,4%
    echo 截取6-12个字符:%var:~6,6%
    echo 截取15-20个字符:%var:~15,5%
    pause

    保存为批处理文件并执行的结果如下:

    原始字符串:abcdefgh

    字符串索引:01234567

    从第3个字符开始截取:cdefgh

    截取前5个字符:abcde

    截取3-6个字符:cdef

    截取6-12个字符:gh

    截取15-20个字符:

    请按任意键继续. . .

       从结果可以看出,上面描述的规则,“m”表示开始截取字符串的位置,“n”表示要截取字符串的长度;然而还可以看出,超过索引的截取是不会导致错误,但是我们还是需要尽量避免超出索引的截取操作。

       上面介绍的例子都是按照顺序进行截取,而批处理变量截取不仅仅支持顺序截取,还支持倒序截取。倒序截取使用负数进行索引和位数的表示,表示从右边开始算起,顺序表示从左边开始算起。来看下面的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @echo off
    set var=abcdefgh
    echo 原始字符串:%var%
    echo 字符串索引:01234567
    echo 字符串倒数索引:87654321
    echo 倒数截取3个字符:%var:~-3%
    echo 从倒数第5个字符开始截取3个字符:%var:~-5,3%
    echo 从第2个字符开始截取到倒数第5个字符位置:%var:~2,-5%
    pause

    将代码保存为批处理文件并执行的结果为:

    原始字符串:abcdefgh

    字符串索引:01234567

    字符串倒数索引:87654321

    倒数截取3个字符:fgh

    从倒数第5个字符开始截取3个字符:def

    从第2个字符开始截取到倒数第5个字符位置:c

    请按任意键继续. . .

       从结果可以得出看出,倒序截取的索引是从“-1”开始的,也就是右边的第一个字符位置为“-1”,第二个字符位置为“-2”,依次类推。

       来总结一下字符串变量的截取规律,用法为“%var:~m,[n]%”,其中“m”表示开始截取字符串的位置索引数值,当“m”值为正数时表示顺序截取,从左边第一个字符(索引为“0”)开始算起,向右依次加一;当“m”值为负数时表示倒序截取,从右边第一个字符(索引为“-1”)开始算起,向左依次减一。“n”为正数时表示要截取的字符个数,表示从“m”位置算起,向右截取“n”个字符;当“n”为负数时表示从“m”位置算起,截取到从右边开始算起的“n”个字符的位置。使用以下的等式来说明:

    ① 在n无值的情况下,当m>=0时表示顺序截取,从左边第一个字符开始算起(索引为0)截取第“m+1”个字符(索引为m)后的所有字符;当m<0时表示倒序截取,从右边第一个字符算起(索引为-1)截取第“m”个字符(索引为-m)后的所有字符。

    ② 在n存在并且m>=0的情况下表示顺序截取,当n>=0时表示从左边第一个字符(索引为0)开始算起截取第“m+1”个字符(索引为m)后“n”个字符;当n<0时表示从左边第一个字符(索引为0)开始算起截取第“m+1”个字符(索引为m)与从右边第一个字符算起(索引为-1)算起第“n-1”个字符(索引为-n-1)之间的所有字符。

    ③ 在n存在并且m<0的情况下表示倒序截取,当n>=0时表示从右边第一个字符算起(索引为-1)的第“m”个字符(索引为-m)开始截取“n”个字符;当n<0时表示截取从右边第一个字符(索引为-1)算起的第“m”个字符(索引为-m)开始与从右边第一个字符算起(索引为-1)算起第“n-1”个字符(索引为-n-1)之间的所有字符。

       也就说当“m”为正整数表示顺序截取,为负整数表示倒序截取,不论正负都表示截取的开始位置;当“n”为正整数表示截取字符的个数,为负整数则表示截取的终止位置。

    DOS批处理的符号总结

    • “@”符号

       关闭命令的回显,用法“@命令行”。

    • “>”符号

       ①输出重定向符号,用在命令语句后,将命令语句的响应信息输出到指定的空文件中(非空则先清空),用法“命令行 > 文件”。

       ②在“findstr /r”命令中表示匹配单词的右边界,需要配合转义字符“”使用,用法“findstr /r "结束字符(串)>" 文件”。

    • “>>”符号

       ①输出重定向符号,用在命令语句后,将命令语句的响应信息输出到指定的文件中(在原文件尾部追加),用法“命令行 >> 文件”。

       ②在“set /a”命令中表示逻辑右移位运算,将左边操作数的二进制码向右移动右边操作数个位数。即去除右边低位,左边高位补0(正数)或1(负数),用法“set /a num1>>num2”。

    • “<”符号

       ①输入重定向符号,用在命令语句后,将指定文件的内容作为命令语句的输入信息进行处理(一般为读取文件内容的一行信息),用法“命令行 < 文件”。

       ②在“findstr /r”命令中表示匹配单词的左边界,需要配合转义字符“”使用,用法“findstr /r "<开始字符(串)" 文件”。

    • “|”符号

       ①管道符号,用在多个命令语句之间,表示将前面命令语句的响应输出内容作为后面命令语句的输入内容进行处理,用法“命令行 | 命令行”,例如“help | more”。

       ②在“set /a”命令中表示按位或运算,对操作数的二进制码进行位比较,全为0则为0,否则为1,用法“set /a num1|num2”。

    • “^”符号

       ①转义字符,用在特殊字符前面,用于取消该特殊字符的作用。支持的特殊字符有“&”、“|”、“>”、“<”、“!”、“"”等,不包括“%”,用法“^特殊字符”。

       ②在“set /a”命令中表示按位异或运算,对操作数二进制码进行位比较,相同为0,相异为1,用法“set /a num1^num2”。

       ③在“findstr /r”命令的“[]”符号内字符串前表示不匹配“[]”内指定的字符集,用法“findstr /r [^字符(串)] 文件”。

       ④在“findstr”命令中表示一行的开始。

       ⑤在“echo”命令的输出语句中作为续行符号,可以将“^”后的下一行的字符串拼接在当前行后输出。

    • “$”符号

       ①在“prompt”命令中,称为选项转义字符,可以将其后的字符转义为特定的作用效果。

       ②在“findstr”命令中表示一行的结束。

    • “&”符号

       ①逻辑命令符,用在命令语句之间,表示多条命令语句进行连接视为一条语句执行,也就是说无条件的执行符号后的命令语句,用法“命令行 & 命令行”。

       ②在“set /a”命令中表示按位与运算,对操作数的二进制码进行位比较,全为1则为1,否则为0,用法“set /a num1&num2”。

    • “&&”符号

       逻辑命令符,用在命令语句之间,表示只有当符号前命令执行成功时,才执行符号后的命令语句,用法“命令行 && 命令行”,与“||”符号相逆。

    • “||”符号

       逻辑命令符,用在命令语句之间,表示只有当符号前命令执行失败时,才执行符号后的命令语句,用法“命令行 || 命令行”,与“&&”符号相逆。

    • “>&”/“<&”符号

       输入重定向符号的变种,主要用于句柄操作上,其中“>&”表示将一个句柄的输出写入到另一个句柄的输入中;“<&”表示从一个句柄读取输入并将其写入到另一个句柄输出中。这两个符号比较特殊,基本不会用到。

    • “()”符号

       ①在“set /a”命令中表示算术括号优选运算。

       ②在“if”语句中表示语句块。

       ③在“for”语句中表示集合列表范围或语句块。

       ④在组合的命令语句中,表示语句块,可以改变操作符的执行顺序。例如:dir c: && dir D: >a.txt 将之后输出D盘的目录结构;而(dir c: && dir D:)>a.txt可以将C盘和D盘的目录结构都输出。

    • “!”符号

       ①在“set /a”命令中表示逻辑非运算,非0为1,非非0值为0,用法“set /a !num”。

       ②在开启延迟环境变量的模式下,用于引用延迟变量,即在“setlocal”命令后可以使用“!var!”来引用变量作为延迟环境变量处理,也就是说在“setlocal”命令后可以使用“!”来代替“%”,常用在“if”、“for”等复合语句中。

    • “~”符号

       ①在“set /a”命令中表示按位非运算,对操作数的二进制码进行位取反,1变为0,1变为0,用法“set /a ~num”。

       ②临时变量或参数变量增强型扩展符号,常用作对一个表示目录或文件的变量进行扩展操作,例如取得文件名称、文件属性等。大多数用在“for”语句中,对表示文件或目录的临时变量进行扩展引用,例如“%~i”表示去掉路径引号。

       ③字符串变量扩展符号,表示对字符串进行截取操作,用法“%var:~m,n%”。

    • “+”符号

       ①在“set /a”命令中表示算术加法运算,用法“set /a num1+num2”。

       ②在“copy”命令中用于连接需要操作的多个源文件,然后将内容合并在写入目标文件。

    • “-”符号

       ①在“set /a”命令中表示一个负数或者算术减法运算,用法“set /a -mun”或“set /a num1-num2”。

       ②在命令中可以表示选项前缀,替换“/”前缀;用在选项的“/”后表示取该选项操作的反向意义。

       ③范围标识符,在“findstr /r”命令中的表示指定字符范围内的任意字符,例如“[0-9]”表示数字。

    • “*”符号

       ①通配符,表示任意个任意字符。在很多文件和目录管理的命令中可以用于匹配任意文件或目录,例如:在“for /f”的“tokens”选项中表示所有字符。

       ②在“set /a”命令中表示算术乘法运算,用法“set /a num1*num2”。

       ③在“findstr /r”命令中表示将符号前一个字符(串)进行零次或多重匹配。

    • “/”符号

       ①在“set /a”命令中表示算术除法运算,求整除的商,用法“set /a num1/num2”。

       ②选项前缀,在命令后选项前修饰为命令选项,有时可以使用“-”进行替换。

    • “%”符号

       ①在“set /a”命令中表示模运算,求整除后的余数,用法“set /a num1%num2”。

       ②非延迟环境变量引用符号,在批处理中可以使用“%var%”的方式引用环境变量。

       ③在“for”语句中用于定义和引用临时变量,使用“%字母”的方式定义临时变量用于存储当前元素值。

       ④在可以传递参数的命令处理模块,用于引用命令传递的参数,使用“%num”(0<=num<=9)方式引用参数值,其中“%0”表示当前处理模块或批处理文件本身。

       ⑤单字符变量扩展引用符号,使用“%~单字符变量名”的方式来对该变量进行扩展引用,只能在“for”中的临时变量或参数变量上进行扩展。

       ⑥“%”特殊符号的转义字符,在批处理中使用“%%”表示实际的“%”,使用“%%%%”表示实际的“%%”。

    • “<<”符号

       在“set /a”命令中表示左移位运算,对操作数的二进制码进行左移位操作,去除左边高位,右边低位补0。

    • “=”符号

       ①赋值运算符,在“set”命令中表示变量赋值操作。

       ②在“set /a”命令中表示算术运算。在算术运算中可以与其他算术运算符结合使用,表示选进行其他运算,然后在进行赋值操作,结合符号有“*=”、“/=”、“%=”、“+=”、“-=”、“&=”、“^=”、“|=”、“<<=”、“>>=”。

       ③在“echo”命令后表示转义字符或输出空行,紧接“echo”命令。“echo=”用于输出空行,“echo=off”用于输出特殊内容。

    • “,”符号

       ①在“set /a”语句中为多个表达式的分隔符。例如“set /a 1+2,3-2”等。

       ②某些情况下可替换“ ”(空白符)作为命令参数的分隔符。例如“copy a.txt,b.txt”。

       ③在“echo”命令后表示转义字符或输出空行,紧接“echo”命令。“echo,”用于输出空行,“echo,off”用于输出特殊内容。

    • “.”符号

       ①批处理中使用“.”表示当前目录,例如“cd.”;使用“..”表示上一层目录(父级目录),例如“cd..”。

       ②表示文件名的一部分,作为文件名称和文件扩展每次的分隔符。

       ③在“echo”命令后表示转义字符或输出空行,紧接“echo”命令。“echo.”用于输出空行,“echo.off”用于输出特殊内容。

    • “ ”符号

       空白符,表示命令和选项、参数,多个参数等之间的分隔符,某些情况下可以使用“,”替换

    • “?”符号

       ①通配符,表示单个任意字符。

       ②作为命令行语句的特殊选项,用法“命令 /?”,用于查看当前命令说明信息。

    • “""”符号

       ①当文件完全路径名中存在“ ”空白符是,可以使用“""”将路径名引起来作为一个完整路径名进行处理。

       ②在“for /f”命令中表示对扩展选项的引用,当在集合列表中使用“""”表示将当前元素作为字符串进行处理。

       ③在“findstr”或“find”命令中引用的字符串表示要搜索的字符串。

       ④强制作为字符串进行处理,在某些特殊情况下可以使用。

    • “''”符号

       表示命令语句,在“for /f”中的选项集合中使用“''”引起来的语句将会作为命令语句执行并将结果作为“for”语句循环的内容。

    • “;”符号

       ①某些命令参数之间的分隔符,如果该参数可以包含多个值,可以使用“;”进行多个值的分割。

       ②在“echo”命令后表示转义字符或输出空行,紧接“echo”命令。“echo;”用于输出空行,“echo;off”用于输出特殊内容。

    • “[”符号

       ①在“findstr /r”命令中表示字符串范围或类别的开始符号,例如“findstr /r "[0-9]" a.txt”。

       ②在“echo”命令后表示转义字符或输出空行,紧接“echo”命令。“echo[”用于输出空行,“echo[off”用于输出特殊内容。

    • “]”符号

       ①在“findstr /r”命令中表示字符串范围或类别的结束符号,例如“findstr /r "[0-9]" a.txt”。

       ②在“echo”命令后表示转义字符或输出空行,紧接“echo”命令。“echo]”用于输出空行,“echo[off”用于输出特殊内容。

    • “”符号

       ①表示根目录,例如“cd”表示返回到当前根目录。

       ②目录和子目录、目录和文件的路径分隔符。

       ③在“findstr /r”命令中表示转义字符,例如“<”和“>”等。

       ④在“echo”命令后表示转义字符或输出空行,紧接“echo”命令。“echo”用于输出空行,“echooff”用于输出特殊内容。

    • “:”符号

       ①标签声明符号,其后的字符串将作为一个标签进行处理,用法“: 标签名”。可以使用“goto”或“call”命令跳转到该标签处。

       ②磁盘卷标符号,跟在“C”、“D”等卷标后表示盘符。

       ③在单字符变量或字符串变量中表示变量的扩展(替换或截取)操作,例如“%var:~m,n%”表示截取字符串,“%var:str=value%”表示字符串替换操作。

       ④跟在某些命令的特殊选项后表示选项值信息。例如“findstr /C:"abc" a.txt”等。

    • “::”符号

       使用“::”开头的语句表示无效语句,相当于注释语句。

    • “nul”符号

       表示一个空的字符(非空字符串),常见用于“pause > nul”。

    实用案例分析

    1.强制删除目录或文件

       可能会在某些情况下遇到这种情况“某一个文件夹被系统锁定无法删除”,尝试了各种方法都无果,是否很悲观。下面来看看如何使用批处理来解决这一问题。

       首先来看看需要用到的DOS命令,在DOS中删除目录需要使用“md”命令,其中提供“/s”选项用于删除目录树结构,“/q”选项表示静默删除,但是使用“md”命令的限制是必须是空的目录,也就是目录中不能有文件,所有删除目录之前一定要先删除文件,删除文件需要使用“del”命令,其中提供了“/f”选项用于强制删除只读文件,“/a”选项表示删除任意属性的文件,“/q”选项表示静默删除。强制删除目录的代码如下:

    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
    35
    36
    37
    38
    39
    40
    41
    42
    @echo off
    echo ***************强制删除目录*****************
    echo 使用方法:
    echo 1.请输入要删除目录的完整路径地址。
    echo 2.将要删除的目录拖放到执行中的批处理中。
    echo 3.将要删除的目录拖放到程序图标上。
    echo 注意:支持文件删除,删除后无法在回收站恢复。
    echo ********************************************
    echo=
    set inPath=%1
    if defined inPath (
      goto op1
    else (
      goto op2
    )
    :op1
    if exist %inPath% ul (
      rem 删除目录下所有文件(网传有del /f /a /q \?%1做法)
      del /f /a /q %1
      rem 删除当前目录(网传有rd /s /q \?%1做法)
      rd /s /q %1
    else (
      rem 删除目录下所有文件(网传有del /f /a /q \?%1做法)
      del /f /a /q %1
    )
    goto end
    :op2
    set /p inPath=目录完全路径地址(输入或拖放)并回车:
    if exist %inPath% ul (
      rem 删除目录下所有文件
      del /f /a /q %inPath%
      rem 删除当前目录
      rd /s /q %inPath%
    else (
      rem 删除目录下所有文件
      del /f /a /q %inPath%
    )
    goto end
    :end
    echo=
    echo 删除已完成!请刷新看看是否删除。
    pause > nul

    可以将上述代码拷贝下来并保存为批处理文件(例如:删除目录.bat)然后按照用法使用即可。如果你有兴趣可以进行改写或扩展。

    2.锁定目录管理(无法引用的目录)

       在网上看到一些例子,使用DOS命令来制作锁定文件夹,其实这种锁定文件夹是在文件夹的命名上做的文章。来看看如何实现,在DOS(CMD)命令行中进行操作:使用“md D: est..”命令在D盘新建一个“test.”的目录,我们指定在Windows中目录的命令不能以“.”开头或结尾,所以使用“DOS”命令可以打破这个常规,可以尝试一下在D盘中是无法使用Windows系统操作来操作该目录的;然后使用“start D: est..”打开目录;同时可以使用“del D: est..”来删除目录。要想知道这种情况的原理则需要了解Windows实际的工作原理,笔者暂时了解较少,无法解释。所以下面我把上面的内容进行整合一下,代码如下:

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    @echo off
    echo *******************锁定文件夹管理********************
    echo=使用说明:
    echo=1.新建目录必须使用至少一个"."结尾才能锁定进行管理,否则视为普通目录。
    echo=2.打开目录必须使用完全路径名。
    echo=3.删除目录必须首先删除目录中的所有文件。通过打开手动删除。
    echo *****************************************************
    :start
    echo=
    set /p op=请选择以上操作(1.新建/2.打开/3.删除):
    if %op%==1 goto op1
    if %op%==2 goto op2
    if %op%==3 goto op3
    :op1
    set /p dName=请输入新建目录的名称:
    md %dName%.
    if errorlevel 0 (
      echo=%dName%目录新建完成!
    else (
      echo=%dName%目录创建失败!
    )
    goto end
    :op2
    set /p dName=请输入要打开的目录(完整路径):
    start %dName%.
    if errorlevel 0 (
      echo=%dName%目录已打开!
    else (
      echo=%dName%目录打开失败!
    )
    goto end
    :op3
    set /p dName=请输入要删除的目录:
    rd %dName%.
    goto end
    :end
    echo=
    set /p choose=是否退出? (Y/N):
    if /i %choose% equ y (
      exit
    else (
      goto start
    )

    可以将上面代码拷贝下来并保存为批处理文件然后执行试试看。需要注意的时,上面的命令操作都是有一定条件限制的,请参考使用说明。

    3.清理系统垃圾信息

       清理系统垃圾主要是指删除Windows系统内部自动生成的垃圾文件或目录,对Windows系统有所了解的人应该知道垃圾文件主要包括系统补丁的日志文件、系统自动生成的临时文件或目录以及用户使用过程中自动生成的临时文件、缓存文件等垃圾文件(最多的还属于IE的缓存文件),实际的清理就是删除这些文件,删除文件就要使用“del”或“rd”命令来实现。

       在删除这些文件之前一定要知道文件的所在位置,系统的日志和临时文件大多在“WINDOWS”目录下,用户生成的垃圾文件大多都在“我的文档”等的指定文件夹中(可以自行查查哪些文件属于垃圾文件)。下面来看代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @echo off
    rem 使用系统环境变量来获取各个指定的目录地址,系统环境变量可以在系统属性中查看
    echo 正在清理系统垃圾文件,请稍后......
    rem “%systemdrive%”为系统盘符环境变量,一般为“C:”
    del /f /s /q %systemdrive%*.tmp
    del /f /s /q %systemdrive%*.log
    rem “recycled”目录是回收站的目录,如果不清空回收站,则可以注释该语句
    del /f /s /q %systemdrive% ecycled*.*
    rem “%windir%”为系统目录环境变量,一般为“C:WINDOWS”
    del /f /s /q %windir%*.bak
    rem “prefetch”目录为预读文件目录
    del /f /s /q %windir%prefetch*.*
    rem “temp”表示临时工作目录
    rd /s /q %windir% emp & md %windir% emp
    rem “%userprofile%”为系统当前用户目录环境变量,一般为“C:Documents and Settings用户名”
    rem “cookies”目录为浏览器“cookie”存放目录
    del /f /q %userprofile%cookies*.*
    rem “Local Settings”目录为浏览器缓存目录
    del /f /s /q "%userprofile%Local SettingsTemporary Internet Files*.*"
    del /f /s /q "%userprofile%Local SettingsTemp*.*"
    echo 清理系统垃圾完成!
    echo. & pause

    将上面的代码拷贝下来并保存为批处理(.bat)文件,然后执行即可。如有需要,则可以自行添加其他需要清楚的目录和文件,使用的命令主要有“del”和“rd”;如果需要清除并移到“回收站”中,可以使用“move”命令来实现。

    4.重新注册系统组件

       系统组件是系统本身不可缺少的一部分,很多软件缺少了这些组件都无法正常运行。在Windows系统中最基层的系统组件分为DLL和OCX两种,其中DLL(全称Dynamic Link Library,“动态链接库”)文件,它是很多系统软件都依赖的一种对立程序;OCX(全称Object Linking and Embedding (OLE) Control Extension,“嵌入式对象控件”)文件是一种共享式的对立程序。首先了解了这两种组件,那么重新注册则就是将这些DLL或OCX组件卸载后重新安装一遍。那么使用什么命令来执行完成了?

       在Windows系统中提供了一个“regsvr32”外部程序来进行DLL和OCX文件的注册和卸载操作,虽然是一个外部程序,但是同样提供了命令操作行,可以通过在运行窗口或命令行中输入“regsvr32”命令来查看“regsvr32”工具的使用方法,这里不多说,具体选项应用都有说明。需要注意的是“regsvr32”命令只能用于操作“.dll”或“.ocx”文件。下面我们来看重新注册系统组件的代码(这里使用“for”语句来实现):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @echo off
    set dPath=%systemroot%system32
    echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    echo 输入目录,注册其下的所有DLL或OCX组件
    echo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    set /p dPath=请输入你要注册组件的目录(默认为%dPath%):
    for %%f in (%dPath%.dll) do (
      regsvr32 /s %%f
    )
    for %%f in (%dPath%.ocx) do (
      regsvr32 /s %%f
    )

    当系统出现不稳定的情况下,可以使用这种方式修复一下系统。

    5.批量文件重命名操作

       批量文件重命名,这个问题在之前已经说过,但是没有讲过如何实现。下面我们就来看看这个案例。

       或许你在某些网站上下载一系列文件时,这些文件的名称都包含了该网站预定义的部分名称前缀或后缀,是否感觉不雅观,如何去掉这些前缀或后缀呢?一个一个修改?太OUT了!使用批量修改软件?我的第一想法就是别人可以做的批量修改软件我为什么不能。上面已经学习了批处理,那么我们就使用批处理实现简单的批量修改文件名称。

       要修改文件名称,必须要使用“ren”命令,具体操作就是使用“for”循环取到每一个文件名称,然后在名称上进行修改,最后使用新的字符串名称来替换原有的字符串名称即可。代码如下:

    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
    35
    @echo off
    echo #################################################
    echo 使用说明:
    echo 不指定工作路径则为当前所在目录。
    echo 只需要指定需要替换的字符串和替换成的字符串即可。
    echo #################################################
    set dPath=%~dp0
    set /p dPath=设置文件所在目录(默认为%dPath%):
    :start
    set /p oldStr=要替换的字符串:
    set /p newStr=要替换成的字符串:
    if not defined oldStr goto start
    if not defined newStr goto start
    setlocal enabledelayedexpansion
    for /f "skip=4 tokens=3*" %%a in ('dir'do (
      if not %%a==^<DIR^> (
        if not %%b==字节 (
          if not %%b==可用字节 (
            if not %%b==%~nx0 (
              set fileName=%%b
              set fileName=!fileName:%oldStr%=%newStr%!
              ren "%%b" "!fileName!"
            )
          )
        )
      )
    )
    set exitop=n
    set /p exitop=是否退出?(Y/N)
    if /i %exitop% equ y (
      exit
    else (
      goto start
    )
    pause

    上面的批量文件改名只是一个简单的示例,更复杂的改名方案等待你去实现。

    6.进程、端口信息管理

       进程是Windows系统中的一个重要概念,一般对应一个正在执行的程序,在MS-DOS同样提供了对进程实现管理的命令工具,常用的有“tasklist”命令和“taskkill”命令,其中“tasklist”命令用于查看进程信息,可以根据一个进程名称或进程ID来查看进程的相应信息;“taskkill”命令可以用于终止进程,可以根据一个进程名称或进程ID来终止进程或所在进程树。

       端口是Windows系统中的另一个重要概念,具有远程通信功能的程序一般至少需要监听一个端口来实现通信,端口不可以重复使用,一般一个端口只对应一个进程,但是一个进程可以对应多个端口(具体的关于“网络端口“的详细描述可以参考一些其他资料)。在MS-DOS系统中提供了“netstat”工具来查看网络端口,同时还可以查看端口对应的进程信息。下面我们就来实现这个例子:

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    @echo off
    title 端口/进程管理工具
    setlocal enabledelayedexpansion
    :menu
    echo=
    echo ╔-                                                     -╗
    echo           本机开放的端口及使用该端口的进程管理工具
    echo= ..........................................................
    echo       1.TCP/UDP分类列表查看
    echo       2.本地端口查找
    echo       3.进程终止
    echo                                               Q:退出
    echo ╚-                                                     -╝
    echo=
    set op=q
    set /p op=请选择操作:
    if %op%==1 goto seeType
    if %op%==2 goto searchPort
    if %op%==3 goto killProcess
    if /i %op% equ q goto end
    goto menu
    :seeType
    echo=
    echo                        -=TCP协议=-
    echo=
    echo    本地地址       端口      进程ID    进程名称
    echo ─────────────────────────────
    for /f "skip=4 tokens=2,5" %%a in ('netstat -ano -p tcp'do (
      set resultStr=
      rem 拆分本地地址为IP和端口号
      for /f "delims=: tokens=1,2" %%i in ("%%a"do (
         call :builderInfo 15 %%i
         set resultStr1= !resultStr!
         call :builderInfo 6 %%j
         set resultStr2=!resultStr1! !resultStr!
      )
      call :builderInfo 6 %%b
      set resultStr3=!resultStr2! !resultStr!
      rem 通过进程ID获取进程名称
      for /f "skip=2 delims=, tokens=1" %%i in ('tasklist /fi "PID eq %%b" /fo csv'do (
        set resultStr4=!resultStr3! %%~i
      )
      echo !resultStr4!
    )
    echo ==========================================================
    echo=
    echo                       -=UDP协议=-
    echo=
    echo    本地地址       端口      进程ID    进程名称
    echo ─────────────────────────────
    for /f "skip=4 tokens=2,4" %%a in ('netstat -ano -p udp'do (
      set resultStr=
      rem 拆分本地地址为IP和端口号
      for /f "delims=: tokens=1,2" %%i in ("%%a"do (
        call :builderInfo 15 %%i
        set resultStr1= !resultStr!
        call :builderInfo 6 %%j
        set resultStr2=!resultStr1! !resultStr!
      )
      call :builderInfo 6 %%b
      set resultStr3=!resultStr2! !resultStr!
      rem 通过进程ID获取进程名称
      for /f "skip=2 delims=, tokens=1" %%i in ('tasklist /fi "PID eq %%b" /fo csv'do (
        set resultStr4=!resultStr3! %%~i
      )
      echo !resultStr4!
    )
    goto end
    :searchPort
    set /p prot=请输入要查找的端口号(输入b返回主菜单):
    if not defined prot goto :searchPort
    if /i %prot% equ b goto :menu
    echo=
    echo=    -=本地%prot%端口使用明细=-
    echo=
    echo   协议名称   进程ID    进程名称
    echo ─────────────────
    for /f "tokens=1,2,4,5" %%a in ('netstat -ano ^| findstr ":%prot%>"'do (
      for /f %%i in ('echo %%b ^| findstr ":%prot%>"'do (
        set resultStr=
        if /i %%a equ UDP (
          call :builderInfo 6 %%c
          set resultStr1= UDP !resultStr!
          rem 通过进程ID获取进程名称和对应组件
          for /f "skip=2 delims=, tokens=1" %%i in ('tasklist /fi "PID eq %%c" /fo csv'do (
            set resultStr2=!resultStr1! %%~i
          )
        else (
          call :builderInfo 6 %%d
          set resultStr1= TCP !resultStr!
          rem 通过进程ID获取进程名称和对应组件
          for /f "skip=2 delims=, tokens=1" %%i in ('tasklist /fi "PID eq %%d" /fo csv'do (
          set resultStr2=!resultStr1! %%~i
          )
        )
      echo !resultStr2!
      )
    )
    goto end
    :killProcess
    set /p proTag=请输入进程ID或名称(输入b返回主菜单):
    if not defined proTag goto killProcess
    if /i %proTag% equ b goto menu
    for /f %%i in ('echo %proTag% ^| findstr ".exe .dll"'do (
      set /a count=0
      for /f "skip=2 delims=, tokens=1,2,3" %%a in ('tasklist /fi "imagename eq %%i" /fo csv'do (
        set /a count+=1
      )
      set sure=N
      set /p sure=确定结束%proTag%指向的!count!个进程吗?(Y/N
      if /i !sure! equ y (
        taskkill /im %proTag% /f
      else (
        goto killProcess
      )
    )
    set /a num=%proTag%
    if %num%==0 echo 请输入正确进程ID或进程名称,例如123或cmd.exe... &&     goto killProcess
    for /f "skip=2 delims=, tokens=1,2,3" %%a in ('tasklist /fi "pid eq %num%" /fo csv'do (
      set sure=N
      set /p sure=确定结束%num%指向进程吗?(Y/N
      if /i !sure! equ y (
        taskkill /pid %num% /f
      else (
        goto killProcess
      )
    )
    goto end
    :end
    echo=
    set exitop=n
    set /p exitop=是否退出?(Y/N)
    if /i %exitop% equ y (
    exit
    else (
    goto menu
    )
    rem 构建输出信息,根据长度补全空格,是左边对齐
    :builderInfo
    rem 字符串最大长度
    set maxLength=%1
    rem 原始字符串
    set str=%2
    rem 原始字符串长度
    set /a length=0
    rem 计算字符串长度,使用循环截取单个字符是否等于空为依据
    :getLength
    set /a length+=1
    if "%str%"=="" goto fillSpance
    for /f %%i in ("%length%"do (
      if not "!str:~%%i,1!"=="" goto getLength
    )
    rem 使用空格补全字符串,如果原始字符串长度小于最大字符串长度则在后面添加空格
    :fillSpance
    set temp=
    if /i %length% lss %maxLength% (
      for /l %%i in (%length%,1,%maxLength%) do (
        set temp= !temp!
      )
    )
    set resultStr=%str%!temp!

    可以将上面的例子保存为批处理文件执行即可,提供了网络端口的查看工具、根据端口查找进程的工具以及进程终止工具等,同时提供了一个关于字符串长度获取和空格填充的方法,当然你还可以自行进行扩展。

    7.启动或关闭服务

       服务也是Windows系统的一个重要概念,一般服务是其他程序运行的基础环境,关于服务的具体信息可以自行参考其他资料。在MS-DOS提供了一个强悍的工具“net”命令,用于对WIndows基础信息进程综合管理,当然它也可以管理服务。“net”命令如何进行服务的启动和关闭管理呢?来看下面的例子:

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    @echo off
    title 服务管理工具
    setlocal enabledelayedexpansion
    :menu
    echo=
    echo ==================================================
    echo=
    echo                  -=服务管理工具=-
    echo=
    echo              1.启动服务 2.关闭服务
    echo                                        Q.退出
    echo=
    echo 使用说明:启动或关闭服务需要输入服务名称,服务名称
    echo 可以通过“service.msc”管理面板对应属性中查看。
    echo ==================================================
    echo=
    set /p op=请选择操作:
    if %op%==1 goto startService
    if %op%==2 goto closeService
    if /i %op% equ q exit
    goto menu
    :startService
    echo=
    set /p serviceName=请输入你要启动的服务名称:
    for /f "delims=" %%a in ('net start ^| find /i "%serviceName%"'do (
      set /p choice1=%serviceName%服务正在运行...是否关闭?(Y/N^)
      if /i !choice1! equ y (
        net stop %serviceName%
      )
      goto end
    )
    net start %serviceName%
    goto end
    :closeService
    echo=
    set /p serviceName=请输入你要关闭的服务名称:
    for /f "delims=" %%a in ('net start ^| find /i "%serviceName%"'do (
      net stop %serviceName%
      goto end
    )
    set /p choice2=%serviceName%服务处于停止状态...是否开启?(Y/N^)
    if /i %choice2% equ y (
      net start !serviceName!
    )
    goto end
    :end
    echo=
    set exitop=n
    set /p exitop=是否退出?(Y/N)
    if /i %exitop% equ y (
      exit
    else (
      goto menu
    )

    上面的代码中,用到了“net start ...”和“net stop ...”命令,其中“net start”命令用于查看所有已启动的服务列表,“net start ...”命令用于启动指定服务名称的服务,“net stop ...”命令用于关闭指定服务名称的服务。

    8.算法扩展:关于浮点数运算

       MS-DOS批处理脚本支持的数值类型只能是整数类型,如果是小数则将作为字符串进行处理,也就是说默认情况下批处理只支持整数运算,本案例就来介绍一下如何让批处理支持小数运算,案例以小数加法为例进行讲解。

       其实实现过程是一个算法理论,由于批处理支持整数运算,所以需要将小数的整数部分和小数部分分开进行运算。这个地方的运算原理是:分别提取整数部分和小数部分;以原小数中较大的小数的位数为标准进行补0操作,整数部分在右边低位补0,小数部分在左边高位补0;然后去掉小数点,从右边第一个开始依次向左推移并计算其和,大于9则想左边相邻位进1并保留结果个位值,计算完成后还原小数点位置即可。例如:要计算 4567.5+5.6789,则处理后的数字为45675000+00056789,然后按位做加法操作,这个方法只是模拟实现,当然会存在一定的限制。代码如下:

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    @echo off
    :main
    cls
    echo.
    echo 要计算某几个数字的和,请直接敲回车
    echo (注:由于过于复杂和时间问题,原码并非本人编写来自网络)
    echo 退出请输入 e
    echo.
    set num1=0.0
    set times=0
    set expression=
    :input_loop
    set num2=
    set sum_=
    set /a times+=1
    set /p num2= 请输入第 %times% 个数:
    if /i "%num2%"=="e" exit
    if "%num2%"=="" goto result
    if "%num2:~0,1%"=="." set num2=0%num2%
    call :input_check "%num2%" num2
    set expression=%expression%+%num2%
    setlocal enabledelayedexpansion
    for /f "tokens=1-4 delims=." %%i in ("%num1%.%num2%"do (
      set int1=%%i
      set int2=%%k
      set dec1=%%j
      set dec2=%%l
      call :get_length int1 %%i
      call :get_length int2 %%k
      call :get_length dec1 %%j
      call :get_length dec2 %%l
      call :add_zero
      call :sum
      goto input_loop
    )
    :input_check
    rem =========== 检测输入是否正确 ===========
    echo %1|findstr ".">nul||set %~2=%~1.0
    for /f "tokens=1* delims=." %%i in (%1) do (
      echo %%i%%j|findstr "^[0-9]*$">nul || (set /a times-=1&goto input_loop)
    )
    goto :eof
    :get_length
    rem =========== 计算各部分数字的长度 ===========
    set count=0
    :intercept
    set /a count+=1
    for /f %%i in ("%2"do (
      set var=%%i
      if not "!var:~%count%,1!"=="" goto intercept
      set %1_length=!count!
    )
    goto :eof
    :add_zero
    rem =========== 分别在整数部分和小数部分添加0字符串 ===========
    :: 在数位不够的整数部分添0补齐
    set /a int_length_diff=%int1_length%-%int2_length%
    set int_length_diff=%int_length_diff:-=%
    call :creat_zero int_zero %int_length_diff%
    if %int1_length% gtr %int2_length% (
      set int2=%int_zero%%int2%
      set int_length_max=%int1_length%
    else (
      set int1=%int_zero%%int1%
      set int_length_max=%int2_length%
    )
    :: 在数位不够的小数部分添0补齐
    set /a dec_length_diff=%dec1_length%-%dec2_length%
    set dec_length_diff=%dec_length_diff:-=%
    call :creat_zero dec_zero %dec_length_diff%
    if %dec1_length% gtr %dec2_length% (
      set dec2=%dec2%%dec_zero%
      set dec_length_max=%dec1_length%
    else (
      set dec1=%dec1%%dec_zero%
      set dec_length_max=%dec2_length%
    )
    goto :eof
    :creat_zero
    rem =========== 根据数字字符串长度的差异,生成相应长度的0字符串 ===========
    set zero=
    for /l %%i in (1,1,%2) do set zero=!zero!0
    set %1=%zero%
    goto :eof
    :sum
    rem =========== 按位计算新数的和 ===========
    :: 提取整数部分和小数部分来组成新数
    set num1_new=%int1%%dec1%
    set num2_new=%int2%%dec2%
    set /a length_total=%int_length_max%+%dec_length_max%
    set switch=0
    set sum_tmp=
    for /l %%i in (1,1,%length_total%) do (
      set /a sum_tmp=!num1_new:~-%%i,1!+!num2_new:~-%%i,1!+!switch!
      if !sum_tmp! gtr 9 (
        set /a sum_tmp=!sum_tmp!-10
        set switch=1
      else (
        set switch=0
      )
      set sum_=!sum_tmp!!sum_!
    )
    :: 插入小数点
    set sum_=!sum_:~0,-%dec_length_max%!.!sum_:~-%dec_length_max%!
    :: 判断在最高位时是否进位
    if %switch% equ 1 (
      set num1=1%sum_%
    else (
      set num1=%sum_%
    )
    goto :eof
    :result
    if "%expression%"=="" set /a times-=1&goto input_loop
    echo.
    echo %expression:~1%=%num1%
    echo.
    pause
    goto main

    由于时间问题上述代码来自附件中的一个实例,可以自行研究,这里仅供参考。

    9.应用扩展:简单的特效

       曾经在网络上看到一个帖子,楼主写了一个批处理,可以生成一个“I LOVE YOU”图标文件,感觉很是NB。但是这需要借助Windows的第三方脚本工具进行制作。具体的这里不研究,这个批处理附件中也有,可以参考一下代码。这里介绍一个发送给指定电脑一个特殊的文字信息,代码如下:

    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
    @echo off
    set a=10
    set b=0
    :tex
    set /a a+=3
    set /a b+=1
    mode con cols=%a% lines=%b%
    if %a% lss 60 goto :tex
    echo O(∩_∩)O 圣诞快乐 O(∩_∩)O
    set a=15,a6,2e,d0,34,8b,4f,9d,5e
    for %%i in (%a%) do (
      ping -n 2 127.1>nul
      color %%i
    )
    for %%i in (%a%,%a%) do (
      ping -n 1 127.1>nul
      color %%i
    )
    >>ms.txt echo */. . . * .
    >>ms.txt echo .* . [] * __
    >>ms.txt echo */ . ./~~~~~~~~~~~~'. ^|
    >>ms.txt echo *,/,..,\,...........,.
    >>ms.txt echo ^|^| ..▎# ▎田 田 ▎ ^| ▎
    >>ms.txt echo ^|^| ^&^&;▎ ▎ ▎'^|'▎ o
    >>ms.txt echo ^|^| ##■■■■■■■■■■〓
    msg %username% /w /time:3600 <ms.txt
    del ms.txt
    pause

    关于上面的代码,其中“ping -n num 127.1 > nul”这一句表示的是使用“ping”命令来实现延迟操作,这种方式使用的比较广泛。其实上面这个短小的例子的信息都是通过特殊字符进行拼凑的,如果你有艺术细胞,同样可以作出这样的效果。

    后记

       废话、闲话也说了这么多,到这里我对批处理基本东西的整理也就到此结束了,知道了这些信息在去读别人写的批处理脚本应该也不是一件特别费力的事儿了。通过这些介绍,唯一的感受就是批处理程序也一样的强大,其实很多其他的编程语言都提供了对批处理支持接口,可以自行查一下你当前所会的语言的对应接口,调用试试即可。

       关于批处理的学习对应我来说应该是一个过渡性学习,以后不一定会用到,但是很多常用的还是应该记住,现在很多大型的服务器都提供有批处理脚本支持,所以读的懂它还是有一定必要的。别的不多说了,废话就到处结束。

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

    附加内容

    另附批处理编辑工具推荐和实例代码,地址:批处理编辑工具和实例代码

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

  • 相关阅读:
    redis 配置文件
    mysql的join
    mysql在DOS下的操作
    Echart显示在顶端显示总数
    汇编中,BP,SP有何区别?分别怎么使用?
    汇编函数调用中bp和sp是指什么?
    汇编语言中,SP,BP ,SI,DI作用?
    我对读计算机软件专业硕士的几点看法
    磨刀不误砍柴工
    《自己动手写操作系统》读书笔记——初识保护模式
  • 原文地址:https://www.cnblogs.com/ful1021/p/4804393.html
Copyright © 2011-2022 走看看