bat批处理脚本基础
bat批处理基础
一、批处理基础
1. 概念与创建
- 定义:批处理文件是包含一系列 DOS 命令的文本文件,扩展名为
.bat
或.cmd
(.cmd
功能略强,推荐使用)。 - 创建:用记事本编写命令,保存为
文件名.bat
(注意:记事本保存时选择 “所有文件”,编码选 ANSI,避免UTF-8
带BOM
导致乱码)。 - 运行:双击文件或在命令提示符中输入文件名(如
test.bat
)。
2. 基本命令格式
- 命令大小写不敏感:
ECHO
与echo
等效。 - @符号:隐藏当前命令本身的输出(仅显示命令结果)。
- echo 命令:输出文本到控制台;
echo off
关闭后续命令的显示(仅显示结果);@echo off
是批处理常用开头(关闭所有命令显示,仅留结果)。
示例:
@echo off # 关闭后续命令的显示
echo 这是一条输出 # 仅显示“这是一条输出”
echo on # 重新开启命令显示
dir # 会显示“dir”命令本身及结果
基本元素和语法
注释
rem
:注释(会显示空行,可加文本)。::
:注释(更简洁,不显示空行,但在代码块中可能报错,推荐用于单行注释)。
@echo off
rem 这是rem注释(会留空行)
:: 这是::注释(无空行)
echo 执行命令...
关闭命令回显
@echo off
echo 这行命令不会显示命令本身
- 默认情况下,批处理脚本会在执行命令时显示命令本身。使用
@echo off
可以关闭命令回显,@
符号用于防止echo off
命令本身被显示。
输出信息
echo Hello, World!
- 使用
echo
命令向控制台输出文本信息。
@echo off
chcp 936 >nul
REM 设置编码为GBK
echo 你好
pause
chcp 936
命令的作用是临时修改当前批处理脚本运行时所在的终端(CMD 窗口)的编码,仅对当前终端会话有效,具体表现为:- 当批处理脚本运行时,CMD 窗口会临时切换到 GBK 编码(代码页 936),确保脚本中
echo
输出的中文能被正确解析(前提是脚本中的中文本身与 GBK 兼容)。 - 脚本运行结束后,若关闭 CMD 窗口,编码设置会自动失效;若窗口未关闭,手动执行其他命令时,编码仍会保持为 936(但这是当前窗口的局部状态,不影响其他窗口)。
暂停脚本执行
pause
- 使用
pause
命令暂停脚本执行,等待用户按任意键继续。
变量和参数
批处理中的变量用于存储临时数据,分系统变量和自定义变量。
系统变量
系统预设的变量,可直接引用(用
%变量名%
),常用:%windir%
:Windows 安装目录(如C:\Windows
)%userprofile%
:当前用户目录(如C:\Users\用户名
)%time%
:当前时间,%date%
:当前日期%cd%
:当前目录%errorlevel%
:上一条命令的返回值(0 = 成功,非 0 = 失败)
定义和使用变量
set message=Hello, Batch Script!
echo %message%
set /a count=0
- 使用
set
变量名=值
命令定义变量(等号前后无空格),使用%
变量名%
符号引用变量(注意:变量名不区分大小写)。 set /a
:set
命令的/a
参数表示进行算术运算(此处用于变量赋值)。
3. 延迟环境变量扩展
默认情况下,批处理会在代码块(如if
/for
的()
内)预处理时替换变量,导致变量更新后无法实时获取。需用setlocal enabledelayedexpansion
启用延迟扩展,并用!变量名!
引用变量。
示例(问题场景):
@echo off
set num=1
if 1 equ 1 (
set num=2
echo 不启用延迟扩展:%num% # 输出“不启用延迟扩展:1”(预处理时已替换)
)
示例(解决):
@echo off
setlocal enabledelayedexpansion # 启用延迟扩展
set num=1
if 1 equ 1 (
set num=2
echo 启用延迟扩展:!num! # 输出“启用延迟扩展:2”(实时获取)
)
endlocal # 结束延迟扩展(可选)
命令行参数
rem test.bat
echo 第一个参数: %1
echo 第二个参数: %2
- 在批处理脚本中,可以通过
%1
、%2
等引用命令行传递的参数。%0
表示脚本本身的名称。 - 在命令提示符中运行
test.bat param1 param2
,脚本将输出相应的参数。
文件和目录操作
创建目录
mkdir test_folder
md another_folder
- 使用
mkdir
或md
命令创建新的目录。
切换目录
cd test_folder
- 使用
cd
命令切换当前工作目录。
删除目录
rd /s /q test_folder
- 使用
rd
命令删除目录,/s
选项用于删除目录及其所有子目录和文件,/q
选项用于安静模式,不提示确认信息。
创建文件
echo This is a test file. > test.txt
echo Additional content. >> test.txt
- 使用
echo
命令结合重定向符号>
或>>
创建文件并写入内容。>
用于覆盖文件内容,>>
用于追加内容。
删除文件
del test.txt
- 使用
del
命令删除文件。
条件判断
if语句
if "%1"=="hello" (
echo 你输入的参数是 hello
) else (
echo 你输入的参数不是 hello
)
- 用于根据条件执行不同的命令块。
判断文件或者目录是否存在
if exist test.txt (
echo test.txt 文件存在
) else (
echo test.txt 文件不存在
)
- 使用
if exist
语句判断文件或目录是否存在。
字符串比较
if [/i] 字符串1 == 字符串2
:/i
表示不区分大小写。
示例:
@echo off
set str=Hello
if /i %str% == hello ( # /i忽略大小写,Hello与hello等效
echo 字符串匹配
) else (
echo 不匹配
)
数字比较
用专用运算符(注意:不能用==
,需用以下符号):
equ
(等于)、neq
(不等于)、lss
(小于)、leq
(小于等于)、gtr
(大于)、geq
(大于等于)。
示例:
@echo off
set age=18
if %age% geq 18 ( # 18 >= 18
echo 已成年
) else (
echo 未成年
)
错误级别判断
if errorlevel n
:判断上一条命令的返回值是否大于等于 n(常用:0 = 成功,非 0 = 失败)。
示例:
@echo off
copy a.txt b.txt # 假设a.txt不存在,copy失败
if errorlevel 1 ( # 失败时errorlevel >=1
echo 复制失败
) else (
echo 复制成功
)
2. 跳转与标签(goto)
:标签名
:定义标签(标签名自定义,如:menu
)。goto 标签名
:跳转到指定标签(实现循环或分支)。goto :eof
:跳转到批处理末尾(结束脚本)。
示例(简单菜单):
@echo off
:menu # 定义标签menu
echo 1. 显示时间
echo 2. 退出
set /p choice=请输入选择:
if %choice% equ 1 (
echo 当前时间:%time%
goto menu # 回到菜单
) else if %choice% equ 2 (
goto :eof # 结束脚本
) else (
echo 输入错误,请重试
goto menu # 回到菜单
)
循环结构
基础for命令
for %%i in (*.txt) do (
echo 找到文本文件: %%i
)
- 遍历文件:遍历指定目录下的文件,不包含目录。
- 在命令提示符中直接使用时,将
%%i
改为%i
。
for /D命令
@echo off
echo 遍历当前目录下的所有子目录
for /D %%i in (*) do (
echo 子目录: %%i
)
pause
- 遍历当前目录下的所有子目录(不包含文件)
for /L命令
for /l %%i in (1,1,5) do (
echo 当前数字: %%i
)
- 遍历数字范围:使用
for /l
循环遍历数字范围。 - 表示从 1 开始,每次递增 1,直到 5。
for /R命令(递归遍历)
for /R %%i in (*.txt) do echo %%i
for /F命令(解析文本)
for /F "tokens=1,2 delims=," %%i in (data.csv) do echo %%i - %%j
用途:逐行读取文件内容并解析字段
参数说明
delims=分隔符
:指定分割符(默认:空格、制表符)。tokens=n
:取分割后的第 n 部分(n=* 表示取全部)。skip=n
:跳过前 n 行。eol=字符
:忽略以指定字符开头的行(默认:;)。示例 :处理命令输出
获取当前目录下的文件数(用dir /b
列出文件名,再统计行数):@echo off set count=0 for /f %%i in ('dir /b') do ( # 处理dir /b的输出(文件名列表) set /a count+=1 # 计数(/a表示算术运算) ) echo 文件总数:%count%
示例 :分割字符串
@echo off set str=苹果,香蕉,橘子 for /f "delims=, tokens=*" %%i in ("%str%") do ( # 按逗号分割,取全部内容 echo 水果:%%i # 输出“水果:苹果,香蕉,橘子” )
forfiles命令(按条件筛选文件)
forfiles /S /M *.txt /D -7 /C "cmd /c echo @path"
- 用途:筛选最近 7 天内修改过的
.txt
文件(递归) - 常用参数:
/S
:递归子目录/D -7
:7 天内修改的文件/C
:执行的命令
命令对比表
| 命令 | 适用场景 | 是否递归 | 处理对象 |
| ———– | ——————— | ——– | ———– |
| for
| 遍历当前目录文件 | 否 | 文件 |
| for /D
| 遍历当前目录子目录 | 否 | 目录 |
| for /R
| 递归遍历所有文件 | 是 | 文件 |
| for /D /R
| 递归遍历所有子目录 | 是 | 目录 |
| for /L
| 数字循环 | 否 | - |
| for /F
| 解析文本内容 | 否 | 文本行 |
| forfiles
| 按条件筛选文件 / 目录 | 可选 | 文件 / 目录 |
调用其他程序或者脚本
call another_script.bat
call notepad.exe test.txt
使用 call
命令调用其他批处理脚本或可执行程序。
函数定义和调用
@echo off
call :my_function Hello
goto :eof
:my_function
echo 函数接收到的参数: %1
goto :eof
虽然批处理脚本没有像高级编程语言那样的函数定义机制,但可以通过标签和
goto
语句模拟函数。:my_function
是自定义的标签,goto :eof
用于返回调用处。以上是批处理脚本的常见用法,通过组合这些命令和语法,可以实现各种复杂的自动化任务。
错误处理
@echo off
notepad.exe non_existent_file.txt
if errorlevel 1 (
echo 打开文件时出现错误
)
else (
echo 文件打开成功
)
- 在批处理脚本中,错误处理是一个重要的部分。可以使用
if errorlevel
来检查命令执行的返回码,根据不同的返回码执行不同的操作。errorlevel
的值表示命令执行的结果,通常 0 表示成功,非 0 表示失败。
环境变量的使用
@echo off
echo 当前用户的主目录是: %USERPROFILE%
echo 系统可执行文件搜索路径: %PATH%
set NEW_VARIABLE=test_value
echo 新的环境变量值: %NEW_VARIABLE%
- 环境变量是系统中预先定义的变量,可以在批处理脚本中使用。例如,
%USERPROFILE%
表示当前用户的主目录,%PATH%
表示系统的可执行文件搜索路径。还可以使用set
命令查看和修改环境变量。
五、输入与输出
1. 用户输入(set /p)
set /p 变量名=提示文本
:等待用户输入,并将输入值存入变量。
示例:
@echo off
set /p name=请输入姓名:
echo 你好,%name%!
2. 重定向与管道
>
:覆盖写入文件(如echo 内容 > test.txt
)。>>
:追加写入文件(如echo 内容 >> test.txt
)。<
:从文件读取输入(如sort < test.txt
,对 test.txt 内容排序)。|
:管道(前一个命令的输出作为后一个命令的输入,如dir | find "txt"
,查找包含 txt 的文件)。
示例:
@echo off
echo 这是第一行 > test.txt # 覆盖写入
echo 这是第二行 >> test.txt # 追加写入
type test.txt | find "第二行" # 管道:查找包含“第二行”的内容
六、批处理参数
批处理运行时可接收外部参数,用%0
到%9
表示(%0
是脚本名,%1
到%9
是参数,%*
表示所有参数)。
示例(copyfile.bat):
@echo off
rem 功能:复制文件(参数1:源文件,参数2:目标路径)
copy %1 %2 # 复制%1到%2
echo 复制完成:%1 -> %2
运行:copyfile.bat a.txt b.txt
(复制 a.txt 到 b.txt)。
七、常用命令
批处理依赖 DOS 命令完成操作,以下是高频命令及示例:
| 命令 | 功能 | 示例 |
| ——- | ——————————– | ———————————————————— |
| dir
| 列出文件 / 目录 | dir c:\ /b
(只显示文件名,/b:简洁模式) |
| cd
| 切换目录 | cd c:\test
(切换到 c:\test) |
| md
| 创建目录 | md newdir
(创建 newdir 目录) |
| rd
| 删除目录 | rd newdir
(删除空目录);rd /s/q olddir
(/s:删除子目录,/q:静默删除) |
| copy
| 复制文件 | copy a.txt b.txt
(复制 a 到 b);copy *.txt backup\
(复制所有 txt 到 backup 目录) |
| del
| 删除文件 | del a.txt
(删除 a.txt);del /q *.tmp
(/q:静默删除所有 tmp 文件) |
| move
| 移动 / 重命名文件 | move a.txt b.txt
(重命名 a 为 b);move *.txt dir\
(移动所有 txt 到 dir) |
| ren
| 重命名文件 / 目录 | ren old.txt new.txt
|
| cls
| 清屏 | cls
|
| pause
| 暂停(显示 “请按任意键继续…”) | pause
|
| title
| 设置窗口标题 | title 我的批处理
|
| start
| 启动程序 | start notepad.exe
(打开记事本);start "" "c:\program files\test.exe"
(路径带空格需引号,第一个参数为窗口标题) |
| call
| 调用其他批处理 / 标签 | call other.bat
(调用 other.bat);call :sub
(调用本脚本的:sub 标签) |
| exit
| 退出命令提示符 | exit
(关闭当前窗口);exit /b
(仅退出批处理,保留窗口) |
八、高级技巧
1. 变量字符串操作(需延迟扩展)
- 截取:
!变量:~开始位置,长度!
(开始位置:0 起,长度省略则取到末尾)。 - 替换:
!变量:原字符=新字符!
(替换所有匹配的字符)。
示例:
@echo off
setlocal enabledelayedexpansion
set str=abc123def
echo 截取前3位:!str:~0,3! # 输出abc
echo 替换123为xyz:!str:123=xyz! # 输出abcxyzdef
endlocal
2. 管道与多命令执行
&
:多命令顺序执行(无论前一个是否成功)。&&
:前一个命令成功才执行后一个(短路与)。||
:前一个命令失败才执行后一个(短路或)。
示例:
@echo off
echo 第一步 & dir # 先输出“第一步”,再执行dir
copy a.txt b.txt && echo 复制成功 # 复制成功才显示“复制成功”
copy c.txt d.txt || echo 复制失败 # 复制失败才显示“复制失败”
3. 转义字符(^)
用于输出特殊符号(如>、<、&
等,这些符号默认有特殊含义)。
示例:
@echo off
echo 输出>:^> # 显示“输出>:>”(不用^会被当作重定向)
echo 输出&:^& # 显示“输出&:&”(不用^会被当作多命令分隔符)
九、注意事项
- 路径带空格:需用引号包裹,如
"c:\program files\test.exe"
。 - 变量名:不区分大小写,且不能用数字开头。
- 编码:保存为 ANSI 编码(记事本默认),避免 UTF-8 带 BOM 导致命令报错。
- 权限:修改系统目录或注册表的脚本需以管理员身份运行。
将name.txt
中的每一行名字,作为文件名创建文件
@echo off
setlocal enabledelayedexpansion
:: 设置代码页为 GBK,确保中文正常显示
chcp 936 >nul
:: 检查 name.txt 是否存在
if not exist "name.txt" (
echo 错误:未找到 name.txt 文件!
goto :eof
)
:: 定义计数器和总数量
set /a count=0
set /a total=0
:: 先统计文件行数(即文件夹数量)
for /f %%a in ('type "name.txt" ^| find /c /v ""') do set /a total=%%a
echo 正在处理 %total% 个文件夹...
:: 逐行读取 name.txt 并创建文件夹
for /f "usebackq delims=" %%i in ("name.txt") do (
set /a count+=1
:: 去除首尾空格
set "folder=%%i"
for /f "tokens=* delims= " %%a in ("!folder!") do set "folder=%%a"
:: 检查文件夹名是否为空
if not "!folder!"=="" (
:: 创建文件夹(如果不存在)
if not exist "!folder!" (
mkdir "!folder!"
echo [!count/%total%] 创建文件夹: "!folder!"
) else (
echo [!count/%total%] 文件夹已存在: "!folder!"
)
) else (
echo [!count/%total%] 跳过空行
)
)
echo.
echo 操作完成!共处理 %count% 个条目。
pause