Windows批处理杂记
exit命令
exit命令用于退出当前的批处理脚本,并返回一个退出代码ExitCode(即返回值)。退出代码通常是一个整数,用于指示脚本执行的状态,例如成功(0)或失败(非零值)。
exit命令的语法为:
1 | exit [/b] [exitCode] |
其中 /b 选项表示仅退出当前批处理脚本的执行,而不会影响调用脚本的父进程。如果不使用 /b 选项,则 exit 命令会终止当前整个的命令处理器进程(CMD.EXE),并返回退出代码给调用者。
exitCode 是一个可选参数,用于指定退出代码。如果未指定退出代码,则默认返回上一个命令的退出代码。
变量延迟扩展
SETLOCAL ENABLEDELAYEDEXPANSION的作用是设置本地变量延迟扩展。
CMD在执行命令前会对脚本进行预处理,在这个过程中,如果有类似%value%这样的变量就会对其进行识别,并且查找这个变量对应的值,从而用该值替换掉变量,这个替换值的过程,就叫变量扩展,这个类似于C/C++中的宏。
请看下面示例:
1 | @echo off |
结果:4
为什么输出是4而不是5呢?
原因是批处理是按行读取命令的(另外例如for命令等,其后用一对圆括号闭合的所有语句也当作一行),在执行之前要完成必要的预处理工作,这其中就包括对该行命令中的变量赋值。上例中,批处理在运行到set a=5 & echo %a%之前,先把这一整句读取并做了预处理(对变量a赋了值),此时%a%当然就是4。
明白这个道理之后,我们将上例修改为如下方式,就可以输出结果5。
1
2
3
4 @echo off
set a=4
set a=5
echo %a%
为了能够让批处理感知变量的动态变化,批处理设计了变量延迟,即在读取了一条完整的语句之后,不立即对该行的变量赋值,而会在单条语句执行之前再进行赋值,也就是说“延迟”了对变量的赋值。
1 | @echo off |
结果:5
由于启动了变量延迟,得到了输出结果5。
变量延迟的启动语句是SETLOCAL ENABLEDELAYEDEXPANSION,并且变量要用一对叹号括起来,否则就没有变量延迟的效果。
调用npm命令无法返回原批处理
需要使用call命令,如:
1 | call npm install |
可以使用%errorlevel%获取命令的执行结果(通常0表示成功),如:
1 | call npm run build-release |
切换脚本的当前目录
有些命令依赖批处理程序的当前目录,如npm、yarn这样的命令。假如项目位于D:\A\B路径,使用批处理(文件位于D:\build.bat)进行自动构建:
1 | @echo off |
运行上面批处理,构建会失败,通常会提示诸如“D:\package.json不存在”的错误,原因是npm命令是批处理程序的当前目录查找package.json文件的,批处理程序的当前目录默认为批处理文件所在的目录,即D:\,D:\package.json不存在,因此构建失败。
可以使用为cd命令指定/d参数来切换批处理程序的当前目录,上面示例可以修改为:
1 | @echo off |
批处理命令换行
当批处理命令过长,如果都写在一行不便于阅读,可以使用^符号进行分割。
1 | call "%qt_src_folder%\configure.bat" -silent -debug-and-release -force-debug-info -strip ^ |
ECHO 处于关闭状态
遇到“ECHO 处于关闭状态”提示,通常是因为输出变量为空导致。
此时需要注意如下情况:
- 批处理变量左右不能有空格。如果有空格,空格会被当成变量名,如
set a =1,变量名实际为a。 - 开启变量延迟扩展后,引用变量需要使用两个
!的方式,如!str_a!。
显示选择项提示用户选择
使用CHOICE命令可以提供用户在指定的选项中选择一项,并使用%ERRORLEVEL%获取选择的值。
CHOICE命令语法如下:
1 | CHOICE [/C choices] [/N] [/CS] [/T timeout /D choice] [/M text] |
如:
1 | CHOICE /C YNC /M "确认请按 Y,否请按 N,或者取消请按 C。" |
运行外部程序
start
使用 start 命令时,当前批处理不会等待外部程序运行结束,而是继续向下执行。
使用 start 命令运行其他批处理和 windows 命令行程序时,还会创建一个新的命令行窗口,并将在新的窗口中运行新的程序,如:
1 | @echo off |
call
使用 call 命令时,当前批处理会等待外部程序或批处理运行结束,然后才继续向下执行。并且始终在当前命令行窗口中运行其他批处理和命令行程序。
直接运行
直接运行与使用 call 命令一样。但直接运行外部批处理时会破坏当前批处理的运行流程,会导致执行流程无法返回到当前批处理继续执行。
1 | @echo off |
上述示例,执行other.bat后,无法返回到当前批处理,从而无法执行echo 4及后面语句。
获取命令的返回值
在 Windows 批处理中,%errorlevel%变量保存着上一个命令的执行结果(即main函数的返回值)。一般来说,0 表示执行成功,非 0 则表示执行失败,具体的非 0 值的含义则取决于具体的命令。
在批处理脚本中,可以根据%errorlevel%的值来进行后续的处理逻辑,例如:
1 | @echo off |
运行结果如下:
1 | 系统找不到文件 un-exist.exe。 |
%errorlevel%是上一个命令的执行结果,因此上面例子中的 9059 是 start 命令的结果,而不是 un-exist.exe 返回的结果。
顺序执行
Windows 批处理提供了&、&&、||、|、>、>>等顺序执行方式,它们区别如下(下面说的执行成功指的是命令返回值为 0):
&顺序执行多条命令,而不管前面命令是否执行成功。&&顺序执行多条命令,当前面命令执行出错,后面的命令将不会执行。||顺序执行多条命令,直到遇到执行成功的命令。|管道命令,将前一个命令的执行结果输出到后一个命令 如:help|more。>文件写入命令,清除原文件中的内容后再写入。>>文件追加写入命令
以管理员权限运行批处理脚本
基本原理:
- 根据 系统自带的cacls.exe 是否能够访问”%SystemDrive%\System Volume Information”文件,来判断当前批处理进程是否具有管理员权限。
- 创建 vbs 脚本到临时目录,然后使用该脚本提权执行当前 bat 文件。
下面是批处理模板,在最后追加需要执行的脚本即可。
1 | @echo off |
在批处理中执行SQL
1 | "%~dp0\mysql-5.6.19-win32\bin\mysql.exe" ^ |