批处理基础

本系列笔记是我在 Windows 平台上,多年工作和生活中积累下来的批处理相关技术点。

UPDATE: 2018-12-18 :

  • 不建议写基于 Windows CMD 的 Batch file,系统切换语言后,字符编码是最大的问题,并且,功能过于基础,组装成应用比较麻烦;
  • 建议安装 Git 客户端,写基于 Bash 的脚本,适用性更强 (对工作帮助更大);或者 PowerShell 。

前话

批处理,维基上是这么定义的:“在DOS、OS/2、微软视窗系统中,是一种用来当成脚本语言运作程序的文件。它本身是文本文件,其中包含了一系列让具备命令行界面的解释器读取并运行的指令。它相当于是类Unix系统下的Shell script。文件扩展名为.bat.cmd,Shell程序逐行运行命令”。

就是在命令行界面(CLI)执行指令,为的就是一个快,省事,偷懒,不依赖其它软件。

Windows 10,8,7,Vista和XP中的命令称为‘CMD命令’或‘命令提示符命令’,而Windows 98/95和MS-DOS中的命令则称为‘DOS命令’。

本篇讲基础,后面的讲实际实用。

基础部分扫一两遍,旨在认识,不在熟悉。


  • .当前目录
  • ..上一层目录
  • \根目录

  • 文件及目录路径:使用反斜杠\,不使用正斜杠/
  • 文件及目录路径:存在空格,使用双引号包裹路径
  • 不可用于文件目录名的字符:\ / : * ? " < > |
  • 需双引号包裹的字符:( ) [ ] { } ^ = ; ! ' + , ` ~ & 空格
  • 转义字符^
  • 需要转义的字符:^<>|&
  • %%自己可以转义自己
  • rem(回显)和::(不回显)注释语句
  • @隐藏命令的回显
  • echo不显示命令本身,只显示执行后结果
  • pause >nul 暂停,隐藏pause显示的信息

常用DOS命令

  • command /? 查看command命令帮助说明
  • cd/chdir /d [drive:][path]
  • md/mkdir [drive:][path]
  • rd/rmdir [/s] [/q] [drive:]path 删除子目录树/安静模式
  • copy /?
  • ren/rename /?
  • move /?
  • del/erase /?
  • attrib /?
  • tree /?
  • dir /?
  • find /?
  • findstr /?
  • sort /?
  • xcopy /?
  • type /?
  • more 逐屏显示输出
  • set 显示、设置或删除 cmd.exe 环境变量。/p 用户输入,/a 数学运算

建议CMD cd到桌面以help >> cli_help.txtcd /? >> cd_help.txt这类方式深入查阅相关命令说明。


if/else 语句

  • if exist判断驱动器、文件或文件夹是否存在
  • if "字符串1"=="字符串2" 判断某两个字符串是否相等
  • if defined str 判断某个变量是否已经被赋值
  • if 数值1 equ 数值2 判断某两个数值是否相等 + equ, equal + gtr, greater than + geq, greater than or equal + lss, less than + leq, less than or equal + neq, no equal

for 语句

for %variable in(set) do command [command-parameters]

  • 遍历目录(directory) for /D %variable in(set) DO command [command-parameters] 如果集中包含通配符,则指定与目录名匹配,而不与文件名匹配。

  • 递归遍历 for /R [[drive:]path] %variable IN (set) DO command [command-parameters] 检查以 [drive:]path 为根的目录树,指向每个目录中的 FOR 语句。如果在 /R 后没有指定目录规范,则使用当前目录。如果集仅为一个单点(.)字符,则枚举该目录树。

  • 计数循环 for /L %variable IN (start,step,end) DO command [command-parameters] 该集表示以增量形式从开始到结束的一个数字序列。 (1,1,5)将产生序列1 2 3 4 5, (5,-1,1)将产生序列5 4 3 2 1.

  • for /F

    • for /F ["options"] %variable IN (file-set文件名) DO command [command-parameters]
    • for /F ["options"] %variable IN ("string"字符串) DO command [command-parameters]
    • for /F ["options"] %variable IN ('command'命令语句) DO command [command-parameters]
- "options"(delims、tokens、skip、eol、userbackq、变量延迟)
解析文本,读取字符串,
eol=str           - 忽略以指定字符打头的行(默认忽略以分号打头的行的功能,因为以分号打头的行在很多语言中都是作为注释语句)
skip=n          - 跳过无关内容,直奔主题
delims=符号列表      - 切分字符串的利器,默认以空格和Tab作分割符
tokens=x,y,m-n  - 定点提取

     %~I          - 删除任何引号("),扩展 %I(形式变量)
     %~fI        - 将 %I 扩展到一个完全合格的路径名
     %~dI        - 仅将 %I 扩展到一个驱动器号
     %~pI        - 仅将 %I 扩展到一个路径
     %~nI        - 仅将 %I 扩展到一个文件名
     %~xI        - 仅将 %I 扩展到一个文件扩展名
     %~sI        - 扩展的路径只含有短名
     %~aI        - 将 %I 扩展到文件的文件属性
     %~tI        - 将 %I 扩展到文件的日期/时间
     %~zI        - 将 %I 扩展到文件的大小
     %~$PATH:I   - 查找列在路径环境变量的目录,并将 %I 扩展
                   到找到的第一个完全合格的名称。如果环境变量名
                   未被定义,或者没有找到文件,此组合键会扩展到
                   空字符串

可以组合修饰符来得到多重结果:

     %~dpI       - 仅将 %I 扩展到一个驱动器号和路径
     %~nxI       - 仅将 %I 扩展到一个文件名和扩展名
     %~fsI       - 仅将 %I 扩展到一个带有短名的完整路径名
     %~dp$PATH:I - 搜索列在路径环境变量的目录,并将 %I 扩展
                   到找到的第一个驱动器号和路径。
     %~ftzaI     - 将 %I 扩展到类似输出线路的 DIR
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  • usebackq,增强型参数

原来的for语句中第一个括号内的写法要做如下变动:

  • 如果第一个括号里的对象是一条命令语句,原来的单引号'要改为后引号`
  • 如果第一个括号里的对象是字符串,原来的双引号"要改为单引号'
  • 如果第一个括号里的对象是文件名,要用双引号"括起来。

for 语句不能直接读取Unicode编码的文本,需要借助typemore


预处理机制

逐条,命令关键字,运算符,开关、参数,变量引用…

所有的变量引用都已被替换成字符串常量,变量值在复合语句内部被改变,不会影响到语句内部的其他任何地方。

延迟变量的扩展行为

在适当位置使用 SetLocal EnableDelayedExpansion 语句,把原本使用百分号对闭合的变量引用改为使用感叹号对来闭合

@echo off
SetLocal EnableDelayedExpansion
set num=0&&echo !num!
pause
1
2
3
4

在适当的位置使用 call 语句,把变量引用的单层百分号对改为双层百分号对

@echo off
set num=0&&call echo %%num%%
pause
1
2
3

为什么要使用变量延迟?因为要让复合语句内部的变量实时感知到变量值的变化。

复合语句有:for 语句、if else 语句、用连接符&||&&连接的语句、用管道符号|连接的语句,以及用括号括起来的、由多条语句组合而成的语句块。


特殊字符

  • @,隐藏命令的回显

  • ~

    • for中表示使用增强的变量扩展
    • set中表示使用扩展环境变量指定位置的字符串
    • set /a中表示按位取反
  • ^

    • 取消特殊字符作用,字符转义;
    • echo输出时,可以将^后的下一行的字符串拼接在当前行后输出
    • set /a中是按位异;
    • findstr /r[]中表示不匹配指定的字符集
  • &

    • 命令连接字符,顺序执行多条命令,不论命令是否执行成功
    • set /a中是按位与
  • |

    • 管道符,就是将上一个命令的输出,作为下一个命令的输入;传输执行结果
    • 在帮助文档中表示其前后两个开关、选项或参数是二选一的
    • set /a中是按位或
  • &&,连接两个命令,&&前命令执行成功,则执行&&后命令;传输执行状态

  • ||,连接两个命令,||前命令执行失败,则执行||后命令。传输执行状态

  • (),命令包含或者是具有优先权的界定符

  • []

    • 在帮助文档表示其中的开关、选项或参数是可选的
    • findstr /r中表示按其中指定的字符集匹配
  • +

    • copy将很多个文件合并为一个文件
    • set /a中是加法
  • -

    • 范围表示符,如日期的查找,for命令里的tokens操作中就可以用到这个字符
    • findstr /r中连接两个字符表示匹配范围;
    • -跟在命令的/后表示取反向的开关。
  • *

    • 通配符,代表任意个任意字符
    • set /a中是乘法
    • findstr /r中表示将前一个字符多次匹配
    • findstr 正则表达式中,.代表任意字符,*代表0个或多个,.*表示0个或多个任意字符
  • /

    • 表示其后的字符(串)是命令的功能开关(选项)
    • set /a中表示除法
  • =

    • 赋值符号,用于变量的赋值
    • set /a中表示算术运算
  • :,标签定位符,可以接受goto命令所指向的标签

  • " "

    • 界定符,带有空格的路径,一些命令也需要" "符号
    • for /f中将表示它们包含的内容当作字符串分析
    • for /f "usebackq"表示它们包含的内容当作文件路径并分析其文件的内容
    • 在其它情况下表示其中的内容是一个完整的字符串,其中的>>><&|、空格等不再转义
  • >

    • 命令重定向符,覆盖方式重定向提示信息
    • findstr /r中表示匹配单词的右边界,需要配合转义字符\使用
  • >>,命令重定向符,追加方式重定向提示信息

  • <

    • 将其后面的文件的内容作为其前面命令的输入
    • findstr /r中表示匹配单词的左边界,需要配合转义字符\使用
  • \

    • 当前路径的根目录
    • findstr /r中表示正则转义字符
  • ' '

    • for /f中表示将它们包含的内容当作命令行执行并分析其输出
    • for /f "usebackq"中表示将它们包含的字符串当作字符串分析
  • .

    • .当前目录,..上一层目录
    • 在路径中的文件名中出现时:最后的一个.表示主文件名与扩展文件名的分隔
  • $,在findstr命令里面表示一行的结束

  • ``,在for /f中表示它们所包含的内容当作命令行执行并分析它的输出

  • ?

    • findstr /r中表示在此位置匹配一个任意字符
    • ?在路径中表示在此位置通配任意一个字符
    • 紧跟在/后表示获取命令的帮助文档
  • !

    • 当启用变量延迟时,使用! !将变量名扩起来表示对变量值的引用
    • set /a中表示逻辑非,比如set /a a=!0,这时a就表示逻辑1
  • % %,非延迟环境变量引用符号

  • ,,相当于空格

  • ;,命令相同的时候,可以将不同的目标用;隔离开来,但执行效果不变。如执行过程中发生错误则只返回错误报告但程序还是会继续执行。

"\>""\<""\@""\|"不能实现自己想要的功能,将特殊字符替换成ASCII表中的十进制数,然后再把ASCII的10进制数换算成ASCII字符处理。


变量

set varName=varValue

set /p var=请输入变量的值:,等待用户输入到var变量中

set /p= hello world! <nul

set /a 运算表达式


内部处理变量

if definedset /a因为都是在内部处理变量,而不是在预处理过程中处理,也就是说不需要使用变量扩展标记,所以天然具有变量延迟的特性;

至于逗号表达式,这是set /a才能处理的特性;

cmd的预处理过程,是把两个表达式理解为一句,而不是一个语句块,所以自然不可能延迟扩展变量。


Windows Command Line |Shell List and Referenceopen in new window


更新日志:

  • 2017-05-15

(本篇结束)

CC BY-NC-ND 4.0

Last Updated: 2021/7/10下午8:54:57
Contributors: xianghongai