BAT 批处理 基础语法 教程
目录
BAT 批处理教程
当Windows为我们打开了五彩缤纷的图形窗口的时候
DOS命中注定会陨落
CMD毫无悬念将萎缩
批处理逐渐趋向无声无息
而powershell的到来,无疑会让更多的人忘记批处理
这是一门即将失传的技艺
这是一块行将就木的领域
然而,命令行工具仍然具有批量处理一切的巨大威力
字符界面仍然是高效操作、方便灵活、简洁快速的代名词
基础语法
特点
- 批处理脚本存储在
文本文件
中,其中包含的命令按顺序
依次执行,其功能是为了自动执行重复的命令序列
- 批处理文件具有特殊的扩展名
BAT或CMD
,可以通过双击、或在命令提示符(cmd.exe
)或在开始 - 运行
行中运行 - 批处理文件通过称为
命令解释器
的系统文件提供的接口(shell
)来识别和执行,在Windows系统上是cmd.exe
- 批处理文件可以读取用户的输入,有if、for等控制结构,支持函数、数组等高级功能,支持正则表达式,
可以包含其他编程代码
编码问题
在windows上,bat文件默认以GBK
编码格式保存(很多开发语言、环境的默认编码为UTF-8
格式),如果文件中有中文或特殊符号,强烈建议以GBK
编码格式保存,否则会因各种各样的问题导致乱码进而导致执行出错!
如果不能修改文件编码格式,例如通过 for 等命令读写其他编码格式的文件,那需要使用CHCP
修改编码格式。具体可用的编码参考 Code Page Identifiers
@echo off & CHCP 65001
:: 会在命令行中输出【Active code page: 65001】的提示
注释
注释有三种:
Rem 注释内容
:Rem相当于命令,如果Rem的行数太多,可能会使代码变慢:: 注释内容
:建议采用这种方式的注释%注释内容%
:行内注释
@echo off
Rem Rem注释在未关闭命令回显时会在屏幕显示出来,而 :: 则什么情况下都不会显示
echo 注释方式三 %行内注释%
变量
命令行参数
可以在调用批处理文件时传递参数,%n
(n为自然数)表示在调用批处理文件时传递的第n个参数:
%0
批处理文件本身,包括完整的路径和扩展名%1
第一个参数%9
第九个参数%*
从第一个参数开始的所有参数
参数%0
具有特殊的功能,可以调用批处理自身
,以达到批处理本身循环的目的,也可以复制文件自身
等等。
@echo off
echo 第一个参数为:%1
copy %0 d:\new_file.bat %最简单的复制文件自身的方法%
set命令
set [/A] varName=value
:: 仅当该值是数值类型时,才可以使用【/A】,才能正确的进行数值计算,否则会被当做字符串进行计算
:: 使用变量的时候,变量需要包含在%符号中,如【%varName%】
set message=Hello World
echo %message%
SET /A a=5
SET /A b=10
SET /A c=%a% + %b%
echo %c%
set /p
用于将用户输入的内容赋值给变量,以回车表示结束
set /p a=请输入姓名:
echo 姓名为:%a%
:: 先显示指定内容(不能为空),再接受用户输入的内容,最后将用户输入的内容赋值给变量
局部与全局变量
set globalvar=默认情况下都是全局变量
SETLOCAL
set var=SETLOCAL后定义的变量只在ENDLOCAL之前有效
set globalvar=SETLOCAL后重新赋的值也只在ENDLOCAL之前有效
echo %var%
echo %globalvar%
ENDLOCAL
echo %var% %会打印:【ECHO 处于关闭状态。】%
echo %globalvar%
环境变量
echo %JAVA_HOME%
判断变量是否定义
SET /A a=5
SET str=包青天
if defined a echo 【变量a存在】
if not defined b echo 【变量b不存在】
if not [%1]==[] echo 【参数存在:%1】
if exist %1 echo 【文件 %1 存在】
字符串
基本操作
set message=字符串
echo 【%message%】
set var=3
set /A var=%var% + %var%
echo 定义为字符串变量后,还可以使用【/A】开关转换为整数:%var%
:: 上面打印内容为【6】,如果不加【/A】,那么打印结果为【3 + 3】
:: 判断字符串是否相等
if [%message%]==[字符串] echo 方式一
if %message%==字符串 echo 方式二
:: 创建一个空字符串
Set a=
if [%a%]==[] echo 检查是否为空字符串
字符串截取
其实和其他语言的规则是一致的,截取的标准格式为:
%var:~num_chars_to_skip%
%var:~num_chars_to_skip,num_chars_to_keep%
即【%var:~fromIndex,length%】
SET a=abcd
echo 【%a:~0%】【%a:~1%】【%a:~2%】【%a:~3%】【%a:~4%】
:: 【abcd】【bcd】【cd】【d】【】
echo 【%a:~-4%】【%a:~-3%】【%a:~-2%】【%a:~-1%】
:: 【abcd】【bcd】【cd】【d】-n和4-n的效果是一样的
echo 【%a:~0,0%】【%a:~0,1%】【%a:~0,2%】【%a:~0,3%】【%a:~0,4%】
:: 【】【a】【ab】【abc】【abcd】
echo 【%a:~0,-4%】【%a:~0,-3%】【%a:~0,-2%】【%a:~0,-1%】
:: 【】【a】【ab】【abc】【abcd】
echo 【%a:~1,1%】【%a:~1,2%】【%a:~2,1%】【%a:~3,1%】【%a:~3,2%】
:: 【b】【bc】【c】【d】【d】
替换子字符串
%str:new=old%
set str=包青天 白 乾涛 包青天
echo 【%str:包青=老%】【%str: =_%】
:: 【老天 白 乾涛 老天】【包青天_白__乾涛_包青天】
删除子字符串
%str:subStr=%
:: 可以认为是一种特殊的替换:将指定字符替换为空
set str=包青天 白 乾涛 包青天
echo 【%str:包青=%】【%str: =%】
:: 【天 白 乾涛 天】【包青天白乾涛包青天】
if/else 语句
基本语法
- 只有 if 语句时,if 语句的小括号是可选的
- 有 else 语句时,if 语句必须带小括号,而 else 语句的小括号是可选的
- if 条件不能加小括号,否则判断条件为 false
SET /A c=5
SET str=包青天
if %c%==5 echo 只有 if 语句时,if 语句的小括号是可选的
if %str%==包青天 (
echo 如果换行的话必须加小括号,且左小括号不能换行--因为换行后就不是一条命令了,右括号不限制
REM 注意:小括号内不能有 :: 格式的注释,可以有REM格式的注释(因为REM是命令)
)
:: 【==】既可以用来判断数值型,也可以用来判断字符串
if [%1]==[] (echo 呵呵) else echo 有 else 语句时,if 语句必须带小括号,而 else 语句小括号可选
if ([%1]==[]) (echo 呵呵) else (echo if 条件不能加小括号,否则判断条件为 false)
嵌套 if 语句
if(condition1) if (condition2) do_something
:: 只有当条件1和条件2都满足时,才会执行 do_something 块中的代码
if errorlevel
环境变量 errorlevel 的初始值为0
,当一些命令执行不成功,就会返回一个数值,如:1 ,2 等。
注意:IF ERRORLEVEL 是用来测试它的上一个DOS命令
的返回值的,注意只是上一个命令的返回值,而且返回值必须依照从大到小次序顺序判断。
if ERRORLEVEL nubmer commend
copy %0 new_file.bat
if errorlevel 0 echo 命令成功完成
copy %0 new/file.bat
if errorlevel 1 echo 命令失败
goto 语句
@echo off & setlocal enabledelayedexpansion
SET /A a=0
:add
set /A a+=1 & echo echo a当前的值为:%a%,a+1后的值为:!a!
if %a% LSS 3 (
goto :add
) else (
goto :end
)
:end
echo 执行完毕,a的值为:!a!
运算符
赋值运算符
SET /A a=3
SET /A a+=5
echo %a%
:: 其他类似的运算还有【a-=5】【a*=5】【a/=5】【a%=5】
算术运算符
SET /A a=5
SET /A b=3
SET /A c=%a%+%b%
SET /A d=%a%-%b%
SET /A e=%b%*%a%
SET /A f=%b%/%a%
SET /A g=%a%/%b%
SET /A h=%b%%%%a%
SET /A i=%a%%%%b%
echo 【%c%】【%d%】【%e%】【%f%】【%g%】【%h%】【%i%】
:: 【8】【2】【15】【0】【1】【3】【2】
关系运算符
SET /A a=5
SET /A b=10
if %a% EQU %b% echo 相等
if %a% NEQ %b% echo 不相等性
if %a% LSS %b% echo 左小于右
if %a% LEQ %b% echo 左小于等于右
if %a% GTR %b% echo 左大于右
if %a% GEQ %b% echo 左大于等于右
逻辑运算符
- 批处理语言配备了一整套布尔逻辑运算符,如
AND
,OR
,XOR
,但只适用于二进制数字 - 对于
TRUE
或FALSE
也没有任何值 - 可用于条件的唯一逻辑运算符是
NOT
运算符 - 为非二进制数字实现
AND/OR
运算符的方法是使用嵌套的IF
条件或goto
语句
逻辑非
SET /A a=5
IF NOT %a%==6 echo 逻辑非运算符NOT的使用
逻辑与
借助 if 语句实现
SET /A a=5
if %a% LSS 6 (
if %a% GTR 4 (
echo 嵌套if实现and的功能
)
)
if %a% LSS 6 if %a% GTR 4 echo 嵌套if实现and的功能
借助 goto 语句实现
SET /A a=5
if not %a% LSS 6 goto end
if not %a% GTR 4 goto end
:: 为了保持和上面if的结构一致,上面是用了两个not,实际肯定是可以不用not的
goto and_function
:and_function
echo 嵌套if实现and的功能
:end
echo end
逻辑或
逻辑或
实现起来比逻辑与
还要复杂一些,一般都需要借助 goto 语句来实现!
不借助 goto 语句实现的情况
这种方式只适合满足条件时要执行的命令比较少的场景,否则会有大量的冗余代码
SET /A a=3
IF %a% LSS 4 (
echo 如果满足条件一,则执行n条命令
) else IF %a% GTR 6 (
echo 否则,如果满足条件二,也会执行相同的n条命令
)
IF %a% LSS 4 (echo 满足条件) else IF %a% GTR 6 (echo 满足条件)
借助 goto 语句实现
SET /A a=5
IF %a% LSS 4 goto or_function
IF %a% GTR 6 goto or_function
goto end
:or_function
echo 嵌套if实现or的功能
:end
echo end
数组
数组类型并没有明确定义为批处理脚本中的类型,但可以模拟出来,但是有些功能使用起来会有诸多限制。
白哥说:其实批处理脚本中的数组就是多个名称类似的
变量
,其本身没有任何特性或语法,只不过因为这些变量的格式比较像C、Java中的数组,而数组又是那么深入人心,所以我们将其当做数组来看待了而已。
数组元素
其实就是一系列相互之间没任何关系的变量!
set a[0]=10
set a[1]=1
set a[1]=11
set a[3]=14
echo 【%a[0]%】【%a[1]%】【%a[2]%】【%a[3]%】【%a[4]%】
:: 【10】【11】【值不确定】【14】【值不确定】
:: 数组中的每个元素都需要使用set命令专门定义
:: 注意,未定义的元素的值是无法确定的,并不一定是没有值(虽然大部分情况都是没有defined、也没有值的)!
数组元素下标为变量
数组元素下标为变量时,可以认为是:一个变量的名称取决于另一个变量!
set a[0]=10
set /a k=0
:: 以下3种方式均可正确访问 a[k]
echo %k%-%a[0]%
call echo %k%-%%a[%k%]%%
setlocal enabledelayedexpansion & echo %k%-!a[%k%]!
:: 因为a[%k%]之前并没有定义(仅仅是定义了a[0]),所以必须`设置本地为延迟扩展`才能正常访问,且访问时必须使用!代替%
数组的长度
没有直接的函数来确定数组中元素的数量,只能通过遍历数组中的值列表手动计算
。
set d[0]=10
set d[1]=11
set x=0
:getArrayLength
if defined d[%x%] (
call echo %x%-%%d[%x%]%%
set /a x+=1
goto :getArrayLength
)
echo 数组长度为 %x%
:: 注意,如果数组元素定义时不连续,这种方法计算出来的值可能就是错误的,核心在于上面的【defined】表达式
在数组中创建结构
set obj[0].Name=包青天
set obj[0].ID=66
set cur.Name=%obj[0].Name%
echo 【%obj[0]%】【%obj[0].Name%】【%cur.Name%】【%cur.ID%】
:: 【】【包青天】【包青天】【11】 cur.ID的值没有定义,所以打印结果是不确定的
函数
函数定义
定义函数的格式
:function_name
Do_something
EXIT /B 0
:: EXIT语句用于确保函数正常退出
调用函数的格式
Call :function_name parameter1, parameter2… parametern
:: 需要确保在主程序中放入【EXIT /B %ERRORLEVEL%】语句,以便将主程序的代码与函数分开
函数的基本用法
可以通过使用%~n
(n代表参数的位置),来在函数内部访问参数
亲测,完全可以省略掉其中的
~
符号
set p=包青天
CALL :function_1
CALL :function_2 a p %p%
EXIT /B %ERRORLEVEL%
:function_1
echo 调用了【%0】函数
EXIT /B 0
:function_2
echo 调用了【%0】函数,参数为【%~1】【%2】【%3】,所有参数为【%*】
EXIT /B 0
函数的返回值
函数可以通过简单地传递变量名称
来处理返回值,这些变量名称将在调用该函数时保存返回值
CALL :function_3 c & echo 一行代码时必须使用延迟变量【!c!】【%c%】
CALL :function_3 d
echo 不是一行代码时两种方式都可以【!d!】【%d%】
set p=包青天
CALL :function_3 %p% & echo 在函数中修改变量的值时,参数不是传入变量的引用【!p!】【%p%】
CALL :function_3 p & echo 而是传入变量的名称【!p!】【%p%】
EXIT /B %ERRORLEVEL%
:function_3
if NOT [%1]==[] set %1=baiqiantao
EXIT /B 0
参数作为输出参数时,此文件不要设置 setlocal enabledelayedexpansion
,且函数内不要使用SETLOCAL、ENDLOCAL
函数中的局部变量
- 函数中的
局部变量
可以用来避免名称冲突,并保持函数本地的变量变化
- 调用
SETLOCAL
命令后可确保命令处理器对所有环境变量
进行备份,并可在调用ENDLOCAL
命令后恢复 - 当到达批处理文件结束时,即通过调用
GOTO:EOF
,ENDLOCAL
被自动调用 - 使用
SETLOCAL
对变量进行本地化允许在函数中自由使用变量名称,而不必担心与函数外使用的变量名称冲突 - 可以
递归
地调用一个函数,使用SETLOCAL
可以确保每个级别的递归都使用自己的一组变量
,即使变量名被重用
set x=Outer
set y=Outer
CALL :function_1 x y & echo 【!x!-!y!】--【%x%-%y%】
CALL :function_2 x y & echo 【!x!-!y!】--【%x%-%y%】
EXIT /B %ERRORLEVEL%
:function_1
set x=Inner1
set %2=Inner1
:: 当没有SETLOCAL时,以上两种set方式都能改变函数外的变量的值
EXIT /B 0
:function_2
SETLOCAL
set x=Inner2
set %2=Inner2
:: 当有SETLOCAL时,函数内部对变量的修改不影响函数外部的变量的值
ENDLOCAL
EXIT /B 0
2019-12-30
本文来自博客园,作者:白乾涛,转载请注明原文链接:https://www.cnblogs.com/baiqiantao/p/12122023.html