本节学习有关批处理的一些比较琐碎、但又比较有价值的一些知识,运用这些知识后,才有条件更好的实现的批处理的功能,并能使批处理摆脱黑白世界而显得更加多姿多彩。废话少说,开讲啦~

环境变量

所谓环境变量,实际上就是C语言里面的“变量”的意思。批处理的变量可以分为两类,由系统定义的系统变量和由用户根据需要自定义的用户变量。

系统变量

批处理的一些变量是由操作系统事先定义好的,可以适用于任何批处理,我们称这些特殊的变量为“系统变量”。系统变量有很多个,包括硬件类、操作系统类、文件路径类、系统时间类等。要查看所有的系统变量,请新打开一个cmd窗口,输入set回车即可。对几个比较常用的变量解释如下:

  • ComputerName 计算机名,即右键 我的电脑–属性–计算机名 选项卡中的“完整的计算机名称”
  • ComSpec cmd.exe完整路径名
  • HomeDrive 系统分区盘符,一般都是C盘,故而HomeDrive=C:
  • Path 可执行文件默认搜索路径。这个东东非常重要!待会儿单独讲解…
  • ProgramFiles 就是系统的Program Files的路径啦,一般都是C:/Program Files,这就是安装软件时默认的安装路径了
  • Prompt 个性化设置cmd提示符的必备武器!不过,我没怎么用过~
  • SystemDrive 包含系统根目录的分区,其实就是HomeDrive了
  • SystemRoot 系统根目录路径,一般都是C:/WINDOWS
  • Temp、Tmp 文件、程序等可使用的临时目录,默认是C:/WINDOWS/Temp或Tmp。几乎所有的程序在运行时都会在这个目录里面“临时”写入文件。一般情况下,程序写入的临时文件都应该被该程序删除,可惜的是,大部分的程序都很健忘,导致这个文件夹占据的空间越来越大,自然也就使我们的系统增肥喽。所以,我们要把它修改到其他分区,并且时时的清理里面的临时文件。
  • UserName 当前用户名,即所登陆的账户名
  • UserProfile 当前用户的配置目录,一般都是C:/Documents and Settings/%UserName%。默认情况下,我们的桌面就是这个目录下面的“桌面”文件夹;我的文档就是这个目录下面的“My Documents”文件夹。所以啦,往桌面上或我的文档里面放东西就是放到这个文件夹下面了,也就是放到C盘了,重装系统时要覆盖C盘内容的,所以桌面上或我的文档里面的东西当然就会Gone with the Wind了~解决方法有两个,一是保持良好的习惯,不把重要文件放到这两个地方;二是,修改默认设置,将这两个文件夹都移到其他分区。
  • WinDir 操作系统路径,其实就是SystemRoot了

用户变量

编写批处理程序时,用户根据需要自己定义的变量称之为用户变量。用户变量类似于C语言里面的变量,仅仅在定义该变量的程序中有效。 用户变量由set命令定义,这是批处理中非常非常重要的一个操作,从而使set命令成为批处理里面使用频率最高的几个命令之一。关于set命令的使用,参考set /?,本教程也会在后面对其进行讲解。

变量引用

前面的几节课里面,我们已经看到了如何引用变量,即直接用变量名操作变量,通过”%”或”!”来获取变量的值。其中,只有在for语句里面重复对同一变量多次赋值时才需要使用”!”,并且在使用”!”调用变量时,要首先“启用延迟环境变量扩充”,启动命令为:SetLocal EnableDelayedExpansion。另外需要说明的是,“启用延迟环境变量扩充”后,所有的”!”都将被视为“取变量值”的特殊符号,即使用”^!”也不能输出符号”!”。若要输出”!”,则需要“停用延迟环境变量扩充”,命令为:SetLocal DisableDelayedExpansion

参数

跟C语言类似,在调用函数或其他批处理时可能需要传递参数。批处理的参数传递分为直接和间接两种传递参数的方法。

直接传递

直接传递参数,即在使用call命令时,不使用任何参数,在子函数或子批处理里面直接对主函数(也称父批处理)里面的变量进行修改。这跟汇编语言里面的参数传递方式类似。

直接传递参数举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
===============================================
@echo off
setlocal enabledelayedexpansion
set var=aCdehiM,?mnrstW y
echo %var%
call :deal
setlocal disabledelayedexpansion
set var=%var:?=!%
echo %var%
pause>nul
exit
:deal
set tm=!var!
set var=
for %%i in (6,3,11,11,16,15,1,4,11,5,12,13,9,0,12,7,15,14,5,10,2,16,18,8) do (
set var=!var!!tm:~%%i,1!
)
goto :eof
===============================================

可以发现,当我们把变量var作为参数赋予子函数:deal后,子函数对var的值进行了修改;当子函数返回后,主函数里面的var的值就已经是子函数里面var被修改后的值了。

该例子中,使用了本节课前面讲到的setlocal enabledelayedexpansion和setlocal disabledelayedexpansion,前者保证了var在for循环里面能够根据我们的意愿进行处理,后者保证了能够正确输出符号”!”。另外例子中还使用了命令set,利用set对字符串进行了处理。还有一个地方使用了语句goto :eof,该语句相当于C语言里面的return或汇编语言里面的RET,即子程序返回命令。需要说明的是,当子函数本身就在批处理文件的末尾的话,我们是可以省略这句话的,比如将此例的goto :eof删除是不会产生任何影响的。

间接传递

间接传递参数,即在使用call命令时,在其后面添加参数,形如call {[:label][ChildBatch]} Parameter1 Parameter2 ... ParameterN。这跟C语言里面传递参数的格式类似。不同于C语言,批处理中的子函数不需要定义形参,更不需要指定参数的个数。传递过来的参数,在子函数或子批处理里面是以%1~%9的形式表示的,即%1~%9分别表示传递过来的第1~9个参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
===============================================
@echo off
call :deal aaa bbb "c c" ddd eee
pause>nul
exit
:deal
echo %%0 = %0
echo %%1 = %1
echo %%2 = %2
echo %%3 = %3
echo %%4 = %4
echo %%5 = %5
===============================================

通过这个例子就可以清晰的看到%n参数表示法的用法。参数列表中包含空格的依旧要用双引号(“)引起来;另外,也可以看到,%0已经变成了子函数的标号了,而不是父批处理的文件名全称。

区别

这两种参数传递方法本质上是没有区别的,形式上,直接传递直接对原变量进行操作,丢失了原变量的值;间接传递则通过%n对原变量进行了简单的备份,并且通用性更强,即不限定原变量的名称。另外,使用%n还有一个非常大的好处,就是可以通过%~*i来加强处理变量的能力。关于%~*i,详细内容参见for /?

针对二者的差别,可以根据情况决定使用哪种传递方式:

  1. 作为参数的变量名固定、且在子函数中不需要对其进行备份的情况下,使用直接传递法;
  2. 若将子函数作为一个通用的程序模块,以适应于对不同变量的处理,或者作为参数的变量不需要备份时,使用间接传递法。

具体使用哪种方法,还需根据实际情况或使用习惯进行选择。

返回值

有些命令在执行之后将会返回一定的错误值(errorlevel),可以通过errorlevel的值判断命令执行的状况。这点类似于C语言里面的exit(num),num就是错误代码。

获取返回值errorlevel的方法就是,在执行命令后,立马调用返回值errorlevel,如echo %errorlevel%或者if %errorlevel%==1等命令。

errorlevel举例:

1
2
3
4
5
6
7
8
9
===============================================
@echo off
reg add HKCU /v try /f>nul
reg delete HKCU /v try /f
if errorlevel 0 (echo 删除成功!) else (echo 删除失败!)
reg delete HKCU /v try /f
if %errorlevel%==0 (echo 删除成功!) else (echo 删除失败!)
pause>nul
===============================================

上面例子中,由于第一成功的删除了注册表,导致第二次因为找不到注册表而宣告失败。同时我们也看到了errorlevel的使用方法,即if errorlevel 0if %errorlevel%==0是一样的。也许你注意到了,里面还有个笑脸呢~O(∩_∩)O哈哈~这就是ASCII码啦,后面跟你讲啊…

一般情况下,程序或命令成功执行时,返回的errorlevel是0,错误时返回1或更高的值。当然,有些命令是没有返回值的,这点需要注意。

嗯,有没有想起前面有个类似的东西啊?对了,那就是||和&&了,这两个符号就是根据errorlevel的值来进行逻辑判断的~

用户交互

批处理,黑框白字是它最著名的特征。虽然当初DOS为人们使用计算机做出了莫大的贡献,但在Windows盛行的今天,人们已经疏远并且惧怕那个黑色的窗口了。微软为了让先天有着批量处理“体力活”能力的DOS避免“冷酷”,便于接近,特意提供了几个小命令,加强批处理的用户交互功能。

视窗

首先我们要DIY它的窗口。使用命令:color、mode、msg。

  1. 设置窗口背景色和字体颜色by color。详细内容参见color /?。
  2. 设置窗口大小by “MODE CON [COLS=c] [LINES=n]”,cols即宽度,lines即高度。
  3. GUI交互窗口by msg。详细内容参见msg /?。
    视窗DIY举例:
    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
    ===============================================
    @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
    ===============================================

声音

呵呵,是不是注意到了批处理没有声音呐?闲话不说,直接做实验吧 _

1
2
3
4
5
6
7
8
9
10
11
===============================================
@echo off
echo 做好准备,响了啊!!
pause
cls
echo echo 怎么样?呵呵,刺激吧~
pause
cls
mshta vbscript:createobject("sapi.spvoice").speak("Hello!")(window.close)
pause
===============================================

speak好像不能讲中文呐~

此处错误,如果tts安装了中文引擎是可以讲中文的。

此外,这个就是调用vbs的方法:vbscript:createobject("sapi.spvoice").speak("Hello!")

控制

在运行批处理的过程中,我们如何干预批处理呢?呵呵,直接点叉叉就可以结束它了!嗯,不错,不过,太野蛮了~

  1. 暂停批处理:直接按键盘上的Pause键喽
  2. 终止批处理:组合键Ctrl+C。不过,有时候它好像响应的不太积极啊…

ASCII码

前面的例子中,我们已经使用过一次ASCII码了,也就是那个笑脸。ASCII码是图形化的符号,可以用来点缀我们的批处理的。

在cmd窗口中我们可以通过任意一个字符的ASCII码来输入该字符,比如Ctrl+GCtrl+N等,字母a-z对应ASCII码的1-26。对于ASCII码大于26的字符,可以通过这个方法来输入:按住Alt键不松,通过小键盘输入ASCII码的十进制值,松开Alt键即可。