批处理脚本就是把一个一个的命令外加一些逻辑控制组合在一起使其可一次都被执行的文本文件。在Linux上为Shell脚本,而在Windows上则为bat脚本。Windows下脚本命令能够执行需要同时满足以下两个条件:
路径
使用以驱动盘符开始的绝对路径,如c:ab.bat
使用从当前目录开始的相对路径,比如 b.bat或者..a..bat
在系统环境变量PATH中指定的某一个目录下,比如%PATH%中包含c:a时,可以在命令行上直接执行b.bat
可执行
后缀是.bat/cmd/com/exe的文件
批处理文件一般需要在命令行下执行,其中95/98下的命令行叫做MS-DOS命令行,而NT系的命令行才叫命令行终端
2. 变量的声明和赋值(set 和=)
批处理脚本的环境变量有延迟解析的问题,即环境变量是在这一行开始执行前就已经被替换掉了的。
可以通过【cmd.exe /v:on】或者【setlocal ENABLEDELAYEDEXPANSION】来避免该问题,或者将块处理中的代码函数化(函数中就不能再使用语句块和setlocal了--针对对象变量)
当使用call a.bat执行完a.bat之后,在a.bat(没有使用setlocal)中使用set命令设置过的变量,在当前脚本中还能够继续被使用,且其值为a.bat中设置过的值
set 变量名=值 如果等号(=)前后有空格的话,那么空格也作为变量名或者值的一部分了
set /a 变量名=算术表达式 计算算术表达式的值,并将将其赋给变量,如【set /a test= %test% * 2】
set /p 变量名=提示信息 这时提示信息会被提示给用户,并等待用户的输入,输入的内容赋值给变量
set 变量名=%变量名%值 在变量末尾追加”值“
set 变量名= 删除变量
set 所有变量的一览
set 变量前缀 所有以变量前缀开头的变量的一览
setlocal/endlocal 局部环境变量的声明,即使没有用endlocal,在批处理脚本结束的时候也会隐含的调用endlocal
一些特殊的环境变量:
变量 内容 UNIX相当
%ERRORLEVEL% 刚刚执行完的命令或者函数的返回值
$?
%0 执行的命令名 $0
%1 %2 … %9 命令或者函数执行时所传递的参数 $1 $2 …
可以使用shift命令参数移位
%* 命令或者函数执行是所传递的所有参数
$* $@
%CMDEXTVERSION%
cmd命令的版本号%CMDCMDLINE%cmd命令启动时候的参数
%PATH%
命令的搜索路径
$PATH
$LD_LIBRARY_PATH
%CD%命令执行的当前路径,注意不是命令的路径
pwd命令,$PWD
%DATE%当前日期
`date +%Y/%m/%d`
%TIME%当前时刻
`date +%H/%M/%S`
%RANDOM%随机数(0~32767)
%PATHEXT%省略后缀的情况下可以执行的文件
通过ftype /?可以查看详情
%OS%OS名
%USERNAME%当前登录的用户名
$USER
%COMPUTERNAME% 机器的计算机名
%HOMEDRIVE%
%HOMEPATH%用户的家目录和驱动盘符
$HOME
%TEMP%
%TMP%临时目录
3. 流程控制
1). if / else条件判断
序号命令例子
说明
1if [not] exist 文件名 ( 命令1 ) [else 命令2]
判断文件是否存在
2
if [not] [/i] 字符串1 == 字符串2 ( 命令1 ) [else 命令2]判断两个字符串是否相等
如果两边都是数字的话,作为数字进行比较
其他情况下作为字符串进行比较
3
if [/i] 字符串1 比较操作符 字符串2 ( 命令1 ) [else 命令2]使用字符串操作符比较两个字符串
4
if [not] errorlevel 错误码 ( 命令1 ) [else 命令2]判断上一个命令的退出码是否大于等于某一个值
5
if cmdextversion 版本号 ( 命令1 ) [else 命令2]判断命令【cmd.exe】的内部版本号是否大于等于指定版本号
6
if defined 变量 ( 命令1 ) [else 命令2]判断指定的变量是否存在
注意:
1. 命令1/命令2 必须要使用()括起来,当要执行多个命令的时候也必须使用()括起来
2. 在判断的==两边,尽量使用{}而不是使用"",因为如果%1中含有"的时候,该判断会出错
3. 在字符串比较的时候,【/i】表示比较的字符串不区分大小写。
4. if和else必须在同一行,或者if和最初的(在同一行,)和else在同一行,else后面必须有空格
IF {%1}=={%2} (
echo eq l.
) ELSE (
echo not eq l.
)
5. 因为没有相当于and 和or这样的操作符,所以不能进行复杂的运算
6. 可以使用的比较操作符如下
序号操作符
说明
1EQU等于/相等
2
NEQ
不等于/不相等
3
LSS
小于
4
LEQ
小于等于
5
GTR
大于
6
GEQ
大于等于
2). for循环
序号使用例子说明
1
for %变量 in (集合) do 命令 [命令行参数]仅对集合中的文件进行循环,不包含目录。即使是以正则表达式的方式指定
2for /d %变量 in (集合) do 命令 [命令行参数]
当使用通配符(如?和*)时,仅对集合中匹配的目录进行循环
3
for /r [[盘符:]路径] %变量 in (集合) do 命令 [命令行参数]以递归的方式对子目录也进行循环
4
for /l %变量 in (开始, 增量, 结束) do 命令 [命令行参数]从开始到结束以增量的方式循环执行
5
for /f ["选项"] %变量 in (文件集合) do 命令 [命令行参数]对指定的文件中的各行进行循环
其中空行会被忽略掉
%变量指每一行中的第一个字段
6
for /f ["选项"] %变量 in (“字符串”) do 命令 [命令行参数]对字符串进行循环
%变量指每一行中的第一个字段
7
for /f ["选项"] %变量 in (‘命令行’) do 命令 [命令行参数]对命令行的输出结果中的各行进行循环,但仅限于标准输出中的各行
%变量指每一行中的第一个字段
8
for /f "usebackq[,选项]" %变量 in (“文件名”) do 命令 [命令行参数]对指定的文件中的各行进行循环
其中空行会被忽略掉。
%变量指每一行中的第一个字段
同5,但可以指定带有空格的文件名
9
for /f "usebackq[,选项]" %变量 in (字符串‘) do 命令 [命令行参数]对字符串进行循环
%变量指每一行中的第一个字段
同6
10
for /f "usebackq[,选项]" %变量 in (·字符串·) do 命令 [命令行参数]对命令行的输出结果中的各行进行循环,但仅限于标准输出中的各行
%变量指每一行中的第一个字段
同7
注意:
1. 关于【%变量】,如果是在批处理文件中时,需要写成【&&变量】,在命令行时为【%变量】。其中变量
可以为a~z或者A~Z之间的任意一个字母,但是该变量名区分大小写。
2. 集合中各个元素的分隔符可以使用逗号(,),空格,分号(;)中的任意一种,或者混合使用,因此像
【%CLASSPATH%】和【%*】这样的变量也可以指定在集合的位置。但是集合中的某个元素包含特殊
字符,比如【(】或者【)】时,需要使用【^】对其进行转义,即写成【^)】的样子。
3. 如果想使用【@】来达到执行时命令行不被显示的目的的话,需要在for前面和do后面的命令前两两个地方
都要加上【@】符号。
4. 在使用/f参数的时候,可以使用双引号指定一下选项。使用空格分隔可以指定多个选项。
选项使用例子
说明
skip=行数
指定从文件的开头开始忽略的行数
eol=行尾字符
for /f "eol=;" %i in (";注释") do echo %i
以指定字符开始的行会被作为注释而忽略掉。也可以理解为指定表示一行结束的字符
delims=分隔符字符集
for /f "delims=,;" %i in ("abc;def,ghi") do echo %i %j %k
默认的分隔符字符集为空格和tab,使用该选项可以变更分隔符字符集。
usebackq
例子见上面的8/9/10
改变在集合中指定的字符串的解释方法。默认不追加双引号的字符串会被认为是文件名。这样的话包含有空格的文件名将无法指定。
如果使用了该选项,则解释如下:
使用双引号括起来的解释为文件名
使用反引号括起来的解释为命令
使用单引号括起来的解释为字符串
tokens=字段1,字段2,字段m-n,*
>for /f "tokens=2" %i in ("a b c") do @echo %i
b
>for /f "tokens=1,3" %i in ("a b c") do @echo %i %j
a c
>for /f "tokens=2-4" %i in ("a b c d e") do @echo %i %j %k
b c d
>for /f "tokens=1,*" %i in ("a b c d e") do @echo %i --- %j
a --- b c d e
>for /f "tokens=*" %i in ("a b c d e") do @echo %i
a b c d e
指定从第几个字段开始赋值给变量,以及取出那些字段。【字段m-n】表示取第m到第n个字段。【*】表示指定的最后一个字段以后剩下的所有字段。
默认为从第一个字段开始赋值给【%变量】。后面的字段会自动的赋值给指定变量名的下一个字母的变量。比如变量指定为【%i】,那么第二个字段会被自动的赋值给【%j】。
3). goto语句和标签
if %~1 == abc goto match
echo 不一致
goto :EOF
:match
echo 一致
使用【:字符串】来声明一个标签,然后使用【goto 标签】来跳到指定的标签出,实现处理的转移
但是EOF是bat脚本中默认的隐含标签,表示到该批处理文件的结尾。因为需要使用【goto :EOF】来表示。
4). switch语句
在批处理脚本中没有switch/case这样的语句,需要使用goto语句来模拟。(如下)
但是要注意,这并不能完全实现。比如不能实现others或者default的功能,
因为如果在goto后面指定一个不存在的标签时,在运行到那里的时候会报批处理脚本的错误。
set case=1
goto caseA_%case%
:caseA_1
echo case1
goto caseA_end
:caseA_2
echo case2
goto caseA_end
:caseA_end
5). 死循环
process_:start
echo do process
goto process_start
6). 函数
定义使用
:func_label
setlocal
~
endlocal
exit /b 返回码
call :func_label
call: func_label 参数列表
echo %errorlevel%
需要注意 延迟环境变量的问题,特别是使用for或者if的语句块时
7) pause 暂停语句,执行到pause语句后,会等待用户的指示,然后继续执行
C:Documents and Settingsuser>pause
请按任意键继续. . .
4. 关于输入输出/重定向(1) 标准输出重定向到文件中(新建一个文件,或者覆盖原有内容)
【格式】 command > filename
【例子】 dir > out.txt
(2) 标准输出追加到既存文件的末尾
【格式】 command >> filename
【例子】 dir >> out.txt
(3) 标准错误重定向到文件中(新建文件或者覆盖原文件内容)
【格式】 command 2> filename
【例子】 dir nonexist.txt 2>stderr.txt
(注)"2"和">"不能存在空格,否则的话2会被解释为命令的参数
(4) 标准输出和错误输出都重定向到文件中(新建文件或者覆盖原文件内容)
【格式】 command > filename 2>&1
【例子】 dir nonexist.txt > out.txt 2>&1
(5) 标准输出和错误输出都重定向到NUL中,不进行显示
【格式】 command 2>NUL 1>NUL
【例子】 dir nonexist.txt 2>NUL 1>NUL
(6) 通过管道符来实现重定向,即将前一命令的标准输出作为后一命令的标准输入
【格式】 command1 |command2
【例子】 type aaa.txt | more
(7) 从文件中读取内容,作为一个命令的输入
【格式】 command1 < file
【例子】 more <aaa.txt
如果是想要标准输入作为for命令的输入时,需要使用管道的形式(command | for语句),即需要借助一个从标准输入读取数据然后又原样输出到标准输出的命令,然后for命令以管道的形式使用那个命令的输出。无论是在脚本外还是脚本内,都需要这样做。如果直接使用文件作为for语句的标准输入时,将会得不到文件中的内容。但是使用管道的话,管道后面的do语句中就不能再使用call 标签的形式了,好像是管道后面被作为了另外一个脚本来处理
(8) 从文件中或者命令行的输出中读取内容进行处理时,请使用for语句的/f选项,具体请参照流程控制中的for语句说明。
(9) 输出到标准输出
【格式】 echo 字符串
【例子】 echo aaaa
如果是输出空行可以使用【echo.】或者【echo]】
5. 脚本中命令/脚本/函数的执行
命令的执行在脚本中直接执行就可以了,如a.exe
脚本的执行,直接执行 a.bat,则a.bat后面的处理将不会再被执行
脚本的执行,如果使用 call a.bat,则a.bat被执行,且脚本中a.bat后面的处理也会被执行,且a.bat中设置的变量也能够继续被访问
函数的执行,关于函数的定义和调用,请参照流程控制中的函数部分说明。
关于命令执行后的退出码的取得,可以通过%ERRORLEVEL%变量来取得,在被执行的脚本或者函数中需要使用 exit /b来返回退出码
关于命令或者被执行的脚本/函数中标准输出的获得,可以参照流程控制中的for语句的说明。
6. 注释
使用【rem】或者【::】来注释。但是被执行的命令还是会被输出出来。比如注释的命令【rem comment】。
如果只是想注释本身不被显示,而被执行的命令被显示出来的话,可以使用【@rem】来进行注释
如果不想被执行的命令也被输出出来,需要执行【echo off】。
但是这个命令本身却会被输出出来,所以需要写成【@echo off】的样子。
7. 关于退出脚本及函数
使用【ERRORLEVEL 】可以取得exit的退出值
1). 退出当前脚本
goto :EOF 或者 exit /B
:EOF是特殊的标签,表示批处理文件的最后
2). 退出函数
exit /B
3). 退出CMD程序
exit 0
对于使用exit退出的脚本,可以使用cmd /c test.bat来执行,这样不会退出终端,
且能使用【ERRORLEVEL 】取得退出值
8. 取字符串字串的操作(正确的说法应该叫环境变量的替换)
下面的用法可以通过【set /?】来查看
x为字符串变量,m是从0开始的,-m的时候m是从1开始的
%x:~m%从第m字符开始一直到最后
m字符~最后
%x:~m,n% 从第m个字符到第n个字符之间的字串,不包含第n个字符
m~n字符
%x:~m,-n% 从第m个字符到倒数第n个字符之间的字串,不包含倒数第n个字符
%x:~-m% 从倒数第m个字符开始到最後
%x:~-m,n% 从倒数第m个字符开始到第n个字符,不包含第n个字符
%x:~-m,-n%从倒数第m个字符开始到倒数第n个字符,不包含倒数第n个字符
%x:a=%将x中的所有a都替换为空
%x:/=%将x中的所有/都替换为
%x:*=%将第一个[]前面的字符(包括)全部替换为空
9. 当脚本参数为文件时的一些方便处理(可以查看for的帮助)
取得文件的目录,盘符,文件名等,这里以第一个参数%1为例: