bat批处理基础

一、批处理基础

1. 概念与创建

  • 定义:批处理文件是包含一系列 DOS 命令的文本文件,扩展名为.bat.cmd.cmd功能略强,推荐使用)。
  • 创建:用记事本编写命令,保存为文件名.bat(注意:记事本保存时选择 “所有文件”,编码选 ANSI,避免 UTF-8BOM 导致乱码)。
  • 运行:双击文件或在命令提示符中输入文件名(如test.bat)。

2. 基本命令格式

  • 命令大小写不敏感ECHOecho等效。
  • @符号:隐藏当前命令本身的输出(仅显示命令结果)。
  • 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 /aset命令的/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
  • 使用 mkdirmd 命令创建新的目录。

切换目录

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 输出&:^&  # 显示“输出&:&”(不用^会被当作多命令分隔符)

九、注意事项

  1. 路径带空格:需用引号包裹,如"c:\program files\test.exe"
  2. 变量名:不区分大小写,且不能用数字开头。
  3. 编码:保存为 ANSI 编码(记事本默认),避免 UTF-8 带 BOM 导致命令报错。
  4. 权限:修改系统目录或注册表的脚本需以管理员身份运行。

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