Windows 批处理脚本(BAT/CMD)完整教程

目录

  1. 基础概念
  2. 变量
  3. 运算符与表达式
  4. 条件判断
  5. 循环结构
  6. 函数定义
  7. 输入输出
  8. 字符串处理
  9. 文件操作
  10. 日期时间处理
  11. 错误处理与调试
  12. 实用技巧
  13. 综合示例

1. 基础概念

1.1 批处理文件简介

批处理文件(Batch File)是 Windows 下扩展名为 .bat.cmd 的文本文件,包含一系列 DOS 命令,用于实现自动化任务。

flowchart LR A[.bat 文件] --> B[命令行解释器 CMD.exe] B --> C[逐行解析] C --> D[执行命令] D --> E[输出结果]

1.2 第一个脚本

@echo off
echo Hello, World!
pause

说明:

  • @echo off - 关闭命令回显(不显示执行的命令本身)
  • echo - 输出文本
  • pause - 暂停,等待用户按键

1.3 注释写法

@echo off
rem 这是单行注释(REM)
:: 这是另一种注释写法
goto :skip_comment
    这里是被跳过的内容
:skip_comment
echo 继续执行

1.4 保留变量

变量 说明 示例值
%~dp0 脚本所在目录(带反斜杠) D:\scripts\
%0 脚本自身路径 D:\scripts\test.bat
%1 - %9 第1-9个命令行参数 传入的值
%* 所有命令行参数 全部参数
%errorlevel% 上一个命令的退出码 0
%date% 当前日期 2026/04/20
%time% 当前时间 14:30:00.00
%random% 0-32767 随机数 12345

2. 变量

2.1 变量基础

flowchart LR A[定义变量] --> B[set var=value] B --> C[使用变量] C --> D[%var%]
@echo off
set name=张三
set age=25
echo 姓名: %name%
echo 年龄: %age%

注意: 等号左右不能有空格,set name = 张三 会把 name (带空格)设为变量名

2.2 延迟变量扩展

@echo off
set num=1
echo 第一种情况(不加延迟):
echo %num%        -- 输出 1
set num=2
echo %num%        -- 仍输出 1(未更新)

echo.
echo 第二种情况(启用延迟):
setlocal enabledelayedexpansion
set num=1
echo !num!        -- 输出 1
set num=2
echo !num!        -- 输出 2(已更新)
endlocal

什么时候需要延迟扩展?

  • iffor 循环内修改变量时
  • 变量在代码块(用括号包围的代码)中赋值时

2.3 变量默认值

@echo off
set name=
echo 默认值用法:
echo %name-default%
echo %name%
set name=李四
echo %name%

2.4 数组模拟

@echo off
setlocal enabledelayedexpansion
set arr[0]=苹果
set arr[1]=香蕉
set arr[2]=橙子

echo 数组元素:
echo !arr[0]!
echo !arr[1]!
echo !arr[2]!

echo.
echo 遍历数组:
for /l %%i in (0,1,2) do (
    echo !arr[%%i]!
)
endlocal

3. 运算符与表达式

3.1 算术运算

@echo off
set a=10
set b=3

set /a sum=a+b
set /a diff=a-b
set /a product=a*b
set /a quotient=a/b
set /a remainder=a%%b

echo 和: %sum%
echo 差: %diff%
echo 积: %product%
echo 商: %quotient%
echo 余数: %remainder%

注意: 取模用 %%,而不是 %

3.2 逻辑运算

@echo off
set /a a=1
set /b b=0

:: 与运算
set /a result=a & b
echo AND: %result%

:: 或运算
set /a result=a ! b
echo OR: %result%

:: 异或运算
set /a result=a ^ b
echo XOR: %result%

:: 非运算
set /a result=!b
echo NOT: %result%

3.3 比较运算(用于 if)

运算符 说明 示例
EQU 等于 if %a% EQU 5
NEQ 不等于 if %a% NEQ 5
LSS 小于 if %a% LSS 5
LEQ 小于等于 if %a% LEQ 5
GTR 大于 if %a% GTR 5
GEQ 大于等于 if %a% GEQ 5

4. 条件判断

4.1 基本 if 语句

@echo off
set score=85

if %score% GEQ 60 (
    echo 及格
) else (
    echo 不及格
)

4.2 嵌套 if

@echo off
set age=25

if %age% GEQ 18 (
    if %age% LSS 30 (
        echo 青年人
    ) else (
        echo 中年人
    )
) else (
    echo 未成年
)

4.3 字符串比较

@echo off
set str1=hello
set str2=hello
set str3=world

if "%str1%"=="%str2%" (
    echo str1 等于 str2
)

if not "%str1%"=="%str3%" (
    echo str1 不等于 str3
)

4.4 检查变量是否为空

@echo off
set name=

if defined name (
    echo name 已定义: %name%
) else (
    echo name 未定义
)

set name=张三
if defined name (
    echo name 已定义: %name%
)

4.5 检查文件/文件夹是否存在

@echo off
set filepath=D:\test.txt
set dirpath=D:\backup

if exist "%filepath%" (
    echo 文件存在
) else (
    echo 文件不存在
)

if exist "%dirpath%" (
    echo 目录存在
) else (
    echo 目录不存在
)

4.6 if 的多层条件

@echo off
set score=78

if %score% GEQ 90 (
    echo 优秀
) else if %score% GEQ 80 (
    echo 良好
) else if %score% GEQ 60 (
    echo 及格
) else (
    echo 不及格
)

5. 循环结构

5.1 for 循环(数字序列)

flowchart LR A[/l 参数] --> B[for /l %%i in (start,step,end)] B --> C[循环体] C --> B
@echo off
echo 打印 1 到 10:
for /l %%i in (1,1,10) do (
    echo %%i
)

echo.
echo 打印 10 到 1:
for /l %%i in (10,-1,1) do (
    echo %%i
)

echo.
echo 打印 0 到 100,步长 10:
for /l %%i in (0,10,100) do (
    echo %%i
)

5.2 for 循环(遍历文件)

@echo off
echo 遍历当前目录下的所有 .txt 文件:
for %%f in (*.txt) do (
    echo 文件: %%f
)

5.3 for 循环(遍历目录)

@echo off
echo 遍历当前目录的所有子目录:
for /d %%d in (*) do (
    echo 目录: %%d
)

5.4 for 循环(递归遍历,/r 参数)

@echo off
echo 递归遍历 D:\test 目录下的所有文件:
for /r D:\test %%f in (*) do (
    echo %%f
)

5.5 for 循环(解析字符串)

@echo off
set fruits=苹果,香蕉,橙子,葡萄

echo 解析逗号分隔的字符串:
for %%f in (%fruits%) do (
    echo水果: %%f
)

5.6 for /f 循环(读取文件)

@echo off
echo 读取文件内容:
for /f "tokens=* usebackq" %%a in ("D:\test.txt") do (
    echo %%a
)

常用选项:

  • tokens=* - 读取整行
  • delims=, - 指定分隔符
  • skip=n - 跳过前 n 行
  • usebackq - 处理带引号或特殊字符的路径

5.7 for /f 解析命令输出

@echo off
echo 解析 ipconfig 输出:
for /f "tokens=2 delims=:" %%a in ('ipconfig ^| findstr /i "ipv4"') do (
    echo IP 地址: %%a
)

6. 函数定义

6.1 基本函数

flowchart LR A[调用函数] --> B[call :函数名] B --> C[执行函数体] C --> D[返回]
@echo off
call :greet 张三
call :greet 李四
goto :eof

:greet
echo 你好, %1!
goto :eof

6.2 带返回值的函数

@echo off
set result=
call :add 10 20 result
echo 计算结果: %result%

set result=
call :multiply 5 6 result
echo 乘积结果: %result%
goto :eof

:add
set /a %3=%1+%2
goto :eof

:multiply
set /a %3=%1*%2
goto :eof

6.3 局部变量

@echo off
set global_var=全局变量
echo 调用函数前: %global_var%

call :test_local

echo 调用函数后: %global_var%
goto :eof

:test_local
setlocal
set global_var=被修改了
set local_var=局部变量
echo 函数内: %global_var%
endlocal
echo 函数内(endlocal后): %global_var%
goto :eof

7. 输入输出

7.1 基本输出

@echo off
echo 第一行
echo 第二行
echo 第三行

:: 关闭当前行的回显
@echo 带有 @ 的行不显示

7.2 用户输入

@echo off
set /p name=请输入您的姓名:
set /p age=请输入您的年龄:

echo.
echo 您的信息:
echo 姓名: %name%
echo 年龄: %age%

7.3 静默输入(隐藏密码)

@echo off
echo 请输入密码(输入不显示):
call :get_password password
echo 您输入的密码是: %password%
goto :eof

:get_password
set /p "input=>"
set "%~1=%input%"
goto :eof

7.4 重定向输出

@echo off
:: 输出到文件(覆盖)
echo 内容 > D:\output.txt

:: 输出到文件(追加)
echo 追加内容 >> D:\output.txt

:: 错误信息重定向
dir nonexistent 2> D:\error.log

:: 同时重定向标准输出和错误
dir D:\nonexistent > D:\all.log 2>&1

:: 丢弃输出
dir > nul 2>&1

7.5 管道

@echo off
:: 查看前 10 行
type D:\test.txt | more

:: 过滤包含关键字的行
type D:\test.txt | findstr "关键词"

:: 统计行数
type D:\test.txt | find /c /v ""

8. 字符串处理

8.1 字符串替换

@echo off
set str=Hello World

echo 替换前: %str%
echo 替换后: %str:World=China%
echo 全部小写: %str:l=a%
echo 去掉空格: %str: =%

8.2 字符串截取

@echo off
set str=abcdefghij

echo 原始字符串: %str%
echo 从第3个字符开始,截取5个: %str:~2,5%
echo 从第3个字符开始到末尾: %str:~2%
echo 最后3个字符: %str:~-3%
echo 去掉最后3个字符: %str:~0,-3%

语法:%str:起始位置,长度%

  • 位置从 0 开始计数

8.3 字符串长度

@echo off
call :strlen str "Hello World" length
echo 字符串长度: %length%
goto :eof

:strlen
setlocal enabledelayedexpansion
set str=%~2
set len=0
for %%a in (^!str^!) do set /a len+=1
endlocal & set "%~3=%len%"
goto :eof

8.4 字符串拼接

@echo off
set str1=Hello
set str2=World
set result=%str1% %str2%
echo 拼接结果: %result%

8.5 去除字符串引号

@echo off
set quoted_str="Hello World"
set unquoted_str=%quoted_str:~1,-1%
echo 去引号后: %unquoted_str%

:: 使用 ~ 扩展
set str=%~quoted_str%
echo 使用 ~ 扩展: %str%

9. 文件操作

9.1 创建文件/文件夹

@echo off
:: 创建文件夹
mkdir D:\backup

:: 创建多层目录
mkdir D:\backup\2026\04\20

:: 创建文件
echo 内容 > D:\test.txt

:: 创建空文件
type nul > D:\empty.txt

9.2 复制文件/文件夹

@echo off
:: 复制单个文件
copy D:\source\file.txt D:\backup\file.txt

:: 复制并重命名
copy D:\source\file.txt D:\backup\newfile.txt

:: 复制整个目录
xcopy D:\source D:\backup\ /E /I /H /Y

:: 参数说明:
:: /E     复制目录和子目录(包括空目录)
:: /I     如果目标不存在,视为目录
:: /H     复制隐藏和系统文件
:: /Y     覆盖时不提示确认

9.3 移动/重命名

@echo off
:: 移动文件
move D:\source\file.txt D:\backup\file.txt

:: 重命名(同一目录内移动)
move D:\oldname.txt D:\newname.txt

9.4 删除文件/文件夹

@echo off
:: 删除文件
del D:\test.txt

:: 删除多个文件
del D:\*.txt

:: 删除文件夹
rmdir D:\backup

:: 删除非空文件夹
rmdir /S /Q D:\backup

:: 参数说明:
:: /S     删除目录及所有子目录
:: /Q     静默模式,不提示确认

9.5 读取文件(逐行)

@echo off
echo 读取文件 D:\test.txt:
for /f "usebackq tokens=*" %%a in ("D:\test.txt") do (
    echo %%a
)

10. 日期时间处理

10.1 获取当前日期时间

@echo off
echo 当前日期: %date%
echo 当前时间: %time%

:: 年月日分开获取
set year=%date:~0,4%
set month=%date:~5,2%
set day=%date:~8,2%
echo 格式化日期: %year%-%month%-%day%

10.2 生成带时间戳的文件名

@echo off
set timestamp=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%
set timestamp=%timestamp: =0%
echo 时间戳: %timestamp%

set backup_file=backup_%timestamp%.zip
echo 备份文件名: %backup_file%

10.3 日期计算(加减天数)

Windows 批处理没有内置的日期运算,通常需要借助 VBS 或 PowerShell:

@echo off
:: 使用 PowerShell 计算日期
for /f %%a in ('powershell -Command "(Get-Date).AddDays(-7).ToString('yyyy-MM-dd')"') do set last_week=%%a
echo 一周前的日期: %last_week%

for /f %%a in ('powershell -Command "(Get-Date).AddDays(30).ToString('yyyy-MM-dd')"') do set next_month=%%a
echo 一个月后的日期: %next_month%

11. 错误处理与调试

11.1 检查上一个命令的返回码

@echo off
dir D:\test.txt
if %errorlevel% EQU 0 (
    echo 文件存在
) else (
    echo 文件不存在
)

:: 或使用 if errorlevel 语法(注意顺序)
if errorlevel 1 (
    echo 上一个命令失败
)

11.2 设置错误模式

@echo off
:: 命令失败时不停止执行
setlocal enabledelayedexpansion
set error_occurred=0

dir D:\nonexistent1 2>nul
if errorlevel 1 set error_occurred=1

dir D:\nonexistent2 2>nul
if errorlevel 1 set error_occurred=1

if !error_occurred! EQU 1 (
    echo 有错误发生
)
endlocal

11.3 启用详细输出调试

@echo off
:: 开启命令回显
echo 调试模式:
set trace=1

if defined trace (
    echo [DEBUG] 开始执行...
    echo [DEBUG] 当前目录: %cd%
)

11.4 常见错误码

错误码 说明
0 执行成功
1 语法错误或命令失败
2 文件未找到
5 访问被拒绝

12. 实用技巧

12.1 环境变量与 setlocal

@echo off
set global=全局变量
echo 调用前: %global%

call :test
echo 调用后: %global%

goto :eof

:test
setlocal
set global=局部修改
echo 函数内: %global%
endlocal
goto :eof

12.2 等待/延迟

@echo off
echo 即将开始等待...
timeout /t 5 /nobreak
echo 等待结束

:: 精确等待(秒)
ping -n 6 127.0.0.1 > nul

12.3 窗口标题设置

@echo off
title 我的批处理脚本
echo 窗口标题已设置

12.4 颜色设置

@echo off
color 02    :: 黑底绿字
color 0C    :: 黑底红字
color 5E    :: 灰底浅绿字

echo 测试颜色

颜色码: 0=黑 1=蓝 2=绿 3=浅绿 4=红 5=紫 6=黄 7=白 8=灰 9=蓝(高亮) A=绿(高亮) B=浅绿(高亮) C=红(高亮) D=紫(高亮) E=黄(高亮) F=白(高亮)

12.5 调用其他批处理

@echo off
echo 主脚本开始
call D:\scripts\sub.bat
echo 主脚本继续

12.6 调用其他程序

@echo off
:: 同步调用(等待完成)
notepad D:\test.txt
echo 记事本已关闭

:: 异步调用(不等待)
start "" notepad D:\test.txt
echo 记事本已启动(并行执行)

12.7 传递参数给程序

@echo off
start "" "D:\Program Files\MyApp\app.exe" --arg1 value1 --arg2 value2

12.8 字符串分割解析

@echo off
set line=name,age,city
set line=%line:,= %
for %%a in (%line%) do echo %%a

13. 综合示例

13.1 自动化备份脚本

@echo off
setlocal enabledelayedexpansion
title 自动备份脚本

:: ========================
:: 配置区
:: ========================
set SOURCE_DIR=D:\MyProject
set BACKUP_DIR=D:\Backup
set RETENTION_DAYS=30
set LOG_FILE=D:\Backup\backup.log

:: ========================
:: 函数定义
:: ========================
goto :main

:log
    echo [%date% %time%] %~1 >> "%LOG_FILE%"
    echo [%date% %time%] %~1
    goto :eof

:cleanup_old
    forfiles /p "%BACKUP_DIR%" /s /d -%RETENTION_DAYS% /c "cmd /c del /q /f @path" 2>nul
    call :log "清理 %RETENTION_DAYS% 天前的备份完成"
    goto :eof

:main
    :: 记录开始
    call :log "========== 备份开始 =========="
    call :log "源目录: %SOURCE_DIR%"
    call :log "目标目录: %BACKUP_DIR%"

    :: 创建备份目录
    if not exist "%BACKUP_DIR%" (
        mkdir "%BACKUP_DIR%"
        call :log "创建备份目录"
    )

    :: 生成时间戳文件名
    set timestamp=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%
    set timestamp=%timestamp: =0%
    set backup_file=%BACKUP_DIR%\backup_%timestamp%.zip

    :: 执行备份
    call :log "正在压缩文件..."
    powershell -Command "Compress-Archive -Path '%SOURCE_DIR%\*' -DestinationPath '%backup_file%' -Force"

    if exist "%backup_file%" (
        set size=0
        for %%A in ("%backup_file%") do set size=%%~zA
        call :log "备份成功: %backup_file% (大小: !size! bytes)"
    ) else (
        call :log "备份失败!"
    )

    :: 清理旧备份
    call :cleanup_old

    call :log "========== 备份完成 =========="
    echo.
    echo 备份完成,按任意键退出...
    pause > nul
    endlocal
    goto :eof

13.2 Tomcat 启动脚本

@echo off
setlocal
title Tomcat Server

:: ========================
:: Tomcat 配置
:: ========================
set CATALINA_HOME=D:\apache-tomcat-10.1.x
set CATALINA_OPTS=-Xms4g -Xmx16g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g
set JPDA_ADDRESS=8000

:: ========================
:: 启动模式选择
:: ========================
if "%1"=="debug" (
    goto :start_debug
) else if "%1"=="service" (
    goto :start_service
) else (
    goto :start_normal
)

:start_normal
    echo 启动 Tomcat(普通模式)...
    call "%CATALINA_HOME%\bin\catalina.bat" start
    goto :eof

:start_debug
    echo 启动 Tomcat(调试模式)...
    call "%CATALINA_HOME%\bin\catalina.bat" jpda start
    goto :eof

:start_service
    echo 安装 Tomcat 服务...
    sc query Tomcat10 > nul 2>&1
    if errorlevel 1 (
        call "%CATALINA_HOME%\bin\service.bat" install
    )
    net start Tomcat10
    goto :eof

:end
    endlocal

13.3 日志分析脚本

@echo off
setlocal enabledelayedexpansion
title 日志分析工具

set LOG_FILE=D:\app\logs\application.log
set ERROR_COUNT=0
set WARN_COUNT=0

if not exist "%LOG_FILE%" (
    echo 日志文件不存在: %LOG_FILE%
    pause
    exit /b 1
)

echo 开始分析日志: %LOG_FILE%
echo =======================================

for /f "usebackq tokens=*" %%a in ("%LOG_FILE%") do (
    set line=%%a

    :: 检查 ERROR
    echo !line! | findstr /i "ERROR" > nul
    if not errorlevel 1 (
        echo [ERROR] !line!
        set /a ERROR_COUNT+=1
    )

    :: 检查 WARN
    echo !line! | findstr /i "WARN" > nul
    if not errorlevel 1 (
        set /a WARN_COUNT+=1
    )
)

echo =======================================
echo 分析完成
echo ERROR 数量: %ERROR_COUNT%
echo WARN 数量: %WARN_COUNT%

if %ERROR_COUNT% GTR 0 (
    echo 警告: 发现 ERROR 日志,请检查!
)

pause
endlocal

附录:常用命令速查表

命令 说明
echo 显示消息
set 设置变量
if 条件判断
for 循环
goto 跳转
call 调用标签或脚本
exit 退出脚本
setlocal 开始局部变量作用域
endlocal 结束局部变量作用域
rem 注释
pause 暂停
cls 清屏
cd 切换目录
dir 列出文件
mkdir 创建目录
copy 复制文件
move 移动文件
del 删除文件
type 显示文件内容
findstr 搜索字符串
find 搜索字符串(更老)
tasklist 列出进程
taskkill 结束进程
netstat 网络状态
ping 测试连接
ipconfig IP 配置
start 启动程序
timeout 延迟等待
forfiles 批量处理文件
set /a 算术运算
set /p 用户输入

提示: 批处理脚本功能相对有限,复杂任务建议使用 PowerShell 或 Python 实现。

posted @ 2026-05-12 11:34  RK5123153  阅读(15)  评论(0)    收藏  举报