你可以使用 @ 放在任何命令的前面,来关闭那个命令的回显,但是命令太多的话,一个个的关闭太过麻烦。可以使用 echo off 关闭后续所有的回显:

:: @ 用来关闭 echo off 自身的回显
@echo off
echo 'bbb'
pause
'bbb'
请按任意键继续. . .

注意:命令自身消失了,没有出现

想要打开回显,可以使用 @echo on

批处理文件

随意创建一个 .txt 文件,然后将后缀改为 .bat 或者 .cmd,就是一个批处理文件了,你可以直接双击这个文件来运行,也可以将其放在 cmd 窗口中将其作为一个可执行文件来运行:

C:\Users\wztshine\Desktop\bat>test.bat   # 在命令行窗口中,作为可执行程序来执行
'bbb'
请按任意键继续. . .
  • @: 关闭回显,屏蔽当前命令自身的回显。
  • %:用途较多。可以用来求余,显示变量,for 循环中的临时变量等。
  • |:管道符号。将前一条命令的输出,作为后续命令的输入。
  • >, >> 重定向符号。
  • < : 输入重定向
  • & :组合命令,它的作用是用来连接 n 个 DOS 命令,并把这些命令按顺序执行,而不管是否有命令执行失败,譬如 dir Z:\ & dir Y:\ & dir C:\
  • && : 这个命令也是把它前后两个命令连接起来,并按这些命令的顺序执行。与 & 命令不同之处在于,只有当前一条命令运行成功后,才会执行后面的命令。
  • || : 连接多个命令,只有当前一条命令失败后,才会执行后续的命令,当碰到执行正确的命令后,将不执行后面所有的命令
  • "" : 双引号代表字符串。并且字符串内部可以嵌套变量:if "%var%"=="abc" echo %var% is abc
  • 尽管不加双引号也可以表示字符串,但是如果字符串中间包含空格,则要加上双引号
  • , : 某些情况下逗号可以被看作空格使用
  • () : 可以将多行命令放在括号中,作为复合语句执行。
  • ! : 启动变量延迟扩展以后,变量由 %var% 的形式,要写成 !var! 的形式。
  • 对于一些特殊符号 ^ > >> & && | || ,需要使用转义符 ^ 进行转义:

    echo ^^
    echo ^>
    echo ^>^>
    echo ^&
    echo ^&^&
    echo ^|
    echo ^|^|
    pause
    

    针对 % ,使用 % 自身进行转义:

    :: 只会输出一个 %
    echo %%
    

    针对 ! , 没有进行延迟变量的情况下,不用转义。(关于变量延迟,见后文)

    如果进行了延迟变量,需要这么做:

    @echo off
    :: 设置延迟变量
    setlocal enabledelayedexpansion
    echo ^^!
    pause
    

    因为在延迟变量时,! 有特殊含义,所以需要转义。第一次预处理会用第一个 ^ 转义第二个 ^,第二次预处理会用 ^ 转义 !

    想要获取帮助信息,可以在 cmd 命令窗口运行 命令 /? , 譬如:

    C:\Users\wztshine>move /?
    移动文件并重命名文件和目录。
    要移动至少一个文件:
    MOVE [/Y | /-Y] [drive:][path]filename1[,...] destination
    要重命名一个目录:
    MOVE [/Y | /-Y] [drive:][path]dirname1 dirname2
      [drive:][path]filename1 指定你想移动的文件位置和名称。
      destination             指定文件的新位置。目标可包含一个驱动器号
                              和冒号、一个目录名或组合。如果只移动一个文件
                              并在移动时将其重命名,你还可以包括文件名。
      [drive:][path]dirname1  指定要重命名的目录。
      dirname2                指定目录的新名称。
    

    你会看到它的用法是这样的:

    MOVE [/Y | /-Y] [drive:][path]filename1[,...] destination
    

    其中,所有中括号 [/Y | /-Y] 代表了这个选项是可选的,可以有也可以没有。/Y | /-Y 代表了这个选项可以设置成 /Y /-Y ,也就是两者之一,不能同时使用。选项的 /- 是等价的:/Y 等同于 -Y, 并且选项是忽略大小写的:

    :: 这几种都是等价的写法
    move /Y c:\Users\a.txt c:\
    MOVE /Y c:\Users\a.txt c:\
    move /y c:\Users\a.txt c:\
    move -y c:\Users\a.txt c:\
    

    参数和变量

    命令行参数

    批处理文件可以接受命令行参数,通过变量 %0, %1%2%3等来获取。其中 %0 代表了程序自身。%1, %2, %3 ... 代表了传递给脚本的参数。

    @echo off
    echo %1 %2
    pause
    
    C:\Users\wztshine\Desktop\bat>test.bat a b c  # 传递了三个参数:a, b, c, 脚本中只接收了2各参数,因此多余的参数会被忽略
    请按任意键继续. . .
    

    set 设置变量

    set 可以用来设置变量

    set [/A] variable=value
    
  • /A : 可选参数。意思是接受一个整数,如果输入的值是字符串等类型,会将这个变量的值设为 0
  • varibale: 变量名
  • value:变量值
  • C:\Users\wztshine\Desktop\bat>set /A var=abc    # 字符串也会变成数字 0
    C:\Users\wztshine\Desktop\bat>set /A var=2.1    # 不支持浮点数
    运算符不存在。
    C:\Users\wztshine\Desktop\bat>set /A var=2
    C:\Users\wztshine\Desktop\bat>set /A var=-10
    C:\Users\wztshine\Desktop\bat>set var=bac    # 设置字符串
    C:\Users\wztshine\Desktop\bat>echo %var%     # 显示变量的值
    

    注意: %变量名% 是获取变量值的固定语法。

    全局变量和局部变量

    默认声明的任何变量都是全局变量。在 SETLOCALENDLOCAL 之间声明的任何变量,都是局部变量:

    @echo off
    set a=10
    :: 这是一个局部变量
    setlocal
    set b=20    
    endlocal
    echo %a%
    :: 此时变量 b 会是未声明的状态,因此不会打印出任何东西
    echo %b%
    pause
    

    双击运行上述文件:

    ECHO 处于关闭状态。 请按任意键继续. . .

    在批处理文件中或者 cmd 的命令行中,你可以直接使用系统定义的环境变量:

    C:\Users\wztshine\Desktop\bat>echo %PATH%       # 显示环境变量, %PATH% 是内置的变量
    D:\AZ\py3.10.1\Scripts\;D:\AZ\py3.10.1\;
    

    创建字符串

    C:\Users\wztshine\Desktop\bat>set var=hello world
    C:\Users\wztshine\Desktop\bat>echo %var%
    hello world
    

    注意,在声明时,字符串不用加引号!否则引号会作为字符串的一部分。

    @echo off
    :: 空字符串
    set var=
    :: 使用 if 语句判断空白字符串, if 命令后续会讲
    if defined var echo "var is not empty"
    pause
    

    字符串判断

    字符串判断时,使用双引号将字符串包裹起来,这样可以防止字符串包含空格。因为默认情况下,cmd会以 空格 将字符串分开。

    @echo off
    :: 判断字符串
    if "A"=="A" echo A^=A
    :: /i 选项可以忽略大小写
    if /i "A"=="a" echo A^=a
    set a=abc
    :: 变量也可以放在引号中
    if "%a%"=="abc" echo %a%^=abc
    pause
    

    字符串拼接

    字符串拼接很简单,只要将变量或者字符串放在一起就行,不用加引号

    set a=hello
    set b=world
    set c=%a% %b%!
    echo %c%
    ::结果:hello world!
    

    字符串长度

    这个例子看不懂没关系,后文会讲 call 以及 :label 的用法

    @echo off
    set str=Hello World
    :: :strLen 是一个代码段,str 是变量, length 是返回值
    call :strLen str length
    :: 打印长度
    echo String is %length% characters long
    pause
    :strLen
    setlocal enabledelayedexpansion
    :strLen_Loop
       if not "!%1:~%len%!"=="" set /A len+=1 & goto :strLen_Loop
    (endlocal & set %2=%len%)
    goto :eof
    

    字符串转数字

    /a 选项代表了声明的是数字。并且 = 右侧支持数学表达式。

    :: var 是个字符串
    set var=23
    :: c 也是字符串
    set c=%var%+5
    echo %c%
    :: /A 选项,就变成了数字 28,因为它支持数学运算
    set /A c=%var%+5
    

    截取字符串

    %变量:~start,end%
    

    上面的 start,end 代表了截取字符串的起始位置,可以是正数和负数

    实例: 注意负号

    set a=123456789
    echo %a:~2,3%
    ::345      从索引2开始,截取3个字符
    echo %a:~2,-1%
    ::345678   从索引2开始,截取到倒数第一个字符
    echo %a:~2%
    ::3456789  从索引2开始,截取到末尾
    echo %a:~-2%
    ::89       截取倒数2个字符
    echo %a:~-5,1%
    ::5        从倒数第5开始,截取一个字符
    echo %a:~-5,-1%
    ::5678     从倒数第5开始,截取到倒数第一个字符
    

    替换/删除字符串

    %变量:旧字符串=新字符串%
    
    @echo off
    set x=hello world
    :: 将 hello 替换成 beautiful
    echo %x:hello=beautiful%
    :: 将 hello 替换成空(删掉)
    echo %x:hello=%
    :: 替换时是忽略大小写的! 下面的例子查找任意大小写的 hello,并替换成大写的 HELLO
    echo %x:HELLO=HELLO%
    pause
    

    注意如果有多个值,它是全部替换的,而不是只替换一次,而且替换是忽略大小写的!

    beautiful world
     world
    HELLO world
    

    使用通配符:

    * 可以匹配任意多个字符。? 可以匹配零个或一个字符。

    C:\Users\wztshine>set a=123456789
    C:\Users\wztshine>echo %a:1*=0%   # 通配符写在右侧不生效,不知为啥
    123456789
    C:\Users\wztshine>echo %a:*4=0%   # 通配符写在左侧才生效
    056789
    

    字符串大小写替换

    看不懂没关系,后续会讲 for 循环:

    @echo off
    setlocal enabledelayedexpansion
    REM 全部转换成大写字母
    set str=http://bbs.BATHOME.net
    set up=A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
    for %%i in (%up%) do (
    	set str=!str:%%i=%%i!
    echo %str%
    pause
    

    简单说说:

  • setlocal enabledelayedexpansion 用来启动变量延迟,因此后面的变量,使用了 !var! 这种格式
  • for 循环来遍历大写字母,然后查找到相应的字母,进行替换。
  • 通过 set 命令可以创建数组

    @echo off 
    :: 0 是索引,1 是值
    set a[0]=1 
    :: 下面这个没有用
    echo %a%
    :: 这样才能打印出索引 0 的值
    echo %a[0]%
    pause
    

    正常修改就行

    @echo off
    set a[0]=1
    set a[0]=2
    

    echo 用来打印信息

    :: 显示回显状态
    :: 显示某个信息
    echo message
    :: 打印一个空行, '.' 可以用 , : ; / [ \ ] + ( = 等任意符号代替
    echo.
    :: 写入内容到文件
    echo message>a.txt
    :: 追加内容到文件
    echo message>>a.txt
    

    echo 显示消息时,还可以将中间的空格替换成任意符号:

    echo.aaa     # 等同于: echo aaa
    

    pause

    pause 用来暂停程序,等待用户按下任意按键来继续:

    C:\Users\wztshine>pause
    请按任意键继续. . .
    

    不想要默认的提示信息,可以将输出重定向:

    pause>nul
    

    set 可以用来声明变量,注意等号左右不要加空格

    C:\>set str=BatHome
    C:\>echo %str%
    BatHome
    

    set 还可以批量赋值:

    :: 用逗号隔开
    set /a a=1+1,b=2+1,c=3+1
    :: 设置相同的值
    set /a x=y=z=1
    

    如果变量值中带有特殊符号,譬如 &, >>, |, <<, ^, +=, =, -=需要加引号

    C:\>set "str=Bat&Home"
    C:\>echo "%str%"
    "Bat&Home"
    

    注意:是将整个表达式都用引号包起来

    数字和运算

    /a 选项可以将字符串变成数字,并且等号右边支持运算表达式

    注意:DOS 计算只能精确到整数,小数采用四舍五入。

    C:\>set x=1    # 字符串
    C:\>set y=2    # 字符串
    C:\>set /a n=%x%+%y%
    C:\>set x=1
    C:\>set y=2
    C:\>set /a n=x+y
    

    注意:等号右边的变量,可以不用加 %

    表达式符号

    没啥好说的,括号里的先执行:set /a a=(1+2)+3

    + - * / %

    加减乘除以及求余;在批处理程序中使用 % 求余时,要使用 %% 来转义自身,如果是在 cmd 命令行窗口求余,则不需要转义。

    @echo 
    set /a a=10%%2
    pause
    

    <<, >>, &, ^, |

    /p 选项可以等待用户输入,从键盘获取内容。

    语法是:set /p 变量=给用户的提示信息

    @echo off
    set /p input=Input a number:
    echo,%input%
    pause
    

    第三行写成:echo,%input% ,为什么加了个 , 呢?这是因为:

  • %input% 有值,, 起到空格的作用,此时这句命令等价于 echo %input%
  • 当用户没有输入值,%input% 也没有值,这句命令此时等同于 echo, 即打印一个空行
  • 假设用户没有输入值,我们也没有使用逗号,就变成了 echo ,会显示 回显 状态的信息,这不是我们想要的
  • 不换行输出

    @echo off
    for %%i in (bat home) do (
    	set /p =%%i<nul
    pause
    

    这个不换行输出的原理,我也不明白。

    命令结果赋值给变量

    @echo off
    REM 利用for语句把命令结果赋值给变量
    for /f "delims=" %%i in ('ping 127.0.0.1 ^| findstr "%%"') do (
        set "PacketLoss=%%i"
    echo %PacketLoss%
    pause
    

    for 语句不懂,可以看下文的 for 命令部分。

    简单说一下:

    for /f 是用来处理字符串的,他可以遍历命令的每一行输出内容, "delims=" 是它的选项,这里用来设置行分隔符为空白符。

    单引号包裹的 ping 127.0.0.1 ^| findstr "%%" 是一个命令。单引号在 for /f 语句中代表了里面包裹的是命令。

    set 还可以用来列出所有以某个字符串开头的变量:

    C:\>set xxx1=A
    C:\>set xxx3=C
    C:\>set xxx2=B
    C:\>set xxx       # 列出所有以 xxx 开头的变量
    xxx1=A
    xxx2=B
    xxx3=C
    

    if 命令

    if 命令可以进行条件判断。if 可以写成命令的格式:if condition (command) 也可以写成 if ... else ... 语句,还有if condition (commands) else if condition (commands) else (...)的形式:

    if condition (commands) else (commands)

    :: 第一种 if 语句
    if condition (
        command
    :: 第二种 if...else... 语句
    if condition (
    ) else (
    :: 第三种 else if 条件: if.. else if... else if... else ..
    if condition (
    ) else if condition2 (   # 可以有多个 else if 
    ) else (
    
  • 圆括号的两侧要加空格!
  • else 一定要和 if 的右括号写在一行!
  • if 中不能进行数学运算如求余,求和 ...;只能进行比较运算如 大于,小于,等于...
  • if condition (
    	commands
    :: 注意,右括号和 else 以及 else 的左括号要放在一行; 
    ) else (
    	commands
    

    实例:判断上一条命令的退出码

    @echo off
    echo bbs.bathome.net | findstr "bat"
    if %errorlevel% equ 0 (
    	echo 找到指定字符串
    ) else (
    	echo 没有找到指定字符串
    pause
    

    判断变量是否声明

    if [not] defined variable
    
    C:\Users\wztshine>set a=20
    C:\Users\wztshine>if defined a echo yes
    

    判断文件或文件夹存在

    if [not] exist "path"
    

    注意:如果判断文件夹,要在文件夹后面加上 \ ,因为它无法区分文件夹和文件

    @echo off
    if exist "C:\Program Files\" (
    	echo 文件夹存在
    ) else (
    	echo 文件夹不存在
    pause
    
    @echo off
    :: 先判断没有叫 1.txt 的文件夹
    if not exist "1.txt\" (
    	:: 再判断叫 1.txt 的文件
        if exist "1.txt" (
            echo 文件存在
        ) else (
            echo 文件不存在
    pause
    
    if 1 == 1 echo yes
    if 2 gtr 10 echo yes
    

    gtr 是大于的意思,下面会讲

    判断字符串

    判断字符串,最好是用双引号包裹起来,以防字符串包含空格导致判断错误。

    if "a" == "a" echo yes
    :: /i 忽略大小写
    if /i "a" == "A" echo yes
    set a=abc
    set b=ABC
    :: 针对变量,我们也可以添加双引号,这是为了避免变量值中包含空格
    if /i "%a%"=="%b%" echo yes
    

    比较运算符

    equ  # 等于
    neq  # 不等于
    lss  # 小于
    leq  # 小于或等于
    gtr  # 大于
    geq  # 大于或等于
    

    批处理if命令字符串比较和ASCII的关系:

  • 数字小于字母。
  • 同一个字母,小写字母小于大写字母。
  • 不同的字母,按照字母表中的顺序排列。
  • for 处理文件

    基础语法:

    for %%variable in (set) do command
    

    for /l 生成数字序列

    /l 可以生成数字列表,这个功能有点像 python 的 range 函数,可以设置起始和终止值以及步长。

    for /l %%variable in (start,step,end) do command
    

    start : 起始值

    step: 步长,起始值每次都加上这个数

    end:结束值

    @echo off
    :: 这里用了大写字母,它是 L
    for /L %%i in (1,2,8) do (
    	:: 会显示 1 3 5 7
        echo %%i
    pause
    

    for /f 遍历字符串、命令输出和文件

    /f 用来格式化显示某个信息,它可以处理字符串,文本内容,甚至一个命令的输出信息

    三种使用语法:

    :: 处理文件
    for /f ["options"] %%variable in (file-set) do command
    :: 处理字符串
    for /f ["options"] %%variable in ("string") do command
    :: 注意,command 用单引号包裹起来,这里单引号有特殊含义,代表里面是要执行的命令,并获取输出
    for /f ["options"] %%variable in ('command') do command
    

    options :是如何显示信息的选项

    options 的选项

    delims

    设置一行的分隔符,可以设置多个。默认的分隔符是空格制表符。当读取到某一行数据时,在这一行中如果遇到分隔符,程序就会将这一行进行分割。

    譬如针对如下文件:

    a.txt:

    我们读取它:

    @echo off
    REM 针对文本的每一行,默认使用空格和制表符作为分隔符
    for /f %%i in (a.txt) do (
        echo,%%i
    pause
    请按任意键继续. . .
    

    你会发现,只打印了 1,3,第一行的 2 和第二行的 4 没有打印出来。这是因为每一行都用空格分割,然后打印分割后的第一个字段。

    我们手动设置分隔符:

    @echo off
    REM 设置分隔符为 . 和 ;
    for /f "delims=.;" %%i in (a.txt) do (
        echo,%%i
    pause
    

    过滤空白行:

    @echo off
    REM 删除空行但是不删除行首的空格或制表符
    for /f "delims=" %%i in (a.txt) do (
    echo,%%i
    pause
    

    双引号作为分隔符

    @echo off
    REM 以双引号作为列分隔符, 获取第二列
    for /f tokens^=2^ delims^=^" %%i in (a.txt) do (
    	echo,%%i
    pause
    

    tokens 也是一个选项,下面会讲,多个选项可以一起使用。^ 的作用是转义字符。

    tokens

    delims 可以对每行进行分割,tokens 用来指定获取哪几个字段(哪几列)。默认获取第一个字段。

    tokens=x,y,m-n
    

    x, y 用来指定获取哪两个列

    m-n 用来指定获取从 m 到 n 列

    现有文件 a.txt 如下:

    A B C D E F G H I J K L M N O P Q R S T U V W X Y        Z
    

    默认获取第一列:

    for /f %%i in (a.txt) do (
        echo,%%i
    pause
    :: 结果:A
    

    获取第 1,3,5,6,7列:

    for /f "tokens=1,3,5-7" %%i in (a.txt) do (
    	echo,%%i %%j %%k %%l %%m
    pause
    

    当我们通过 tokens=1,3,5-7 来指定了5个字段时,尽管在 for循环中我们只定义了一个 %%i, 但是依然我们可以自定义四个变量来接收剩余的字段:%%j, %%k, %%l, %%m 分别接收 3, 5-7 这些字段

    获取第一列,以及后续所有的列:

    for /f "tokens=1,*" %%i in (a.txt) do (
        echo,%%i
        echo,%%j
    pause
    ::结果:
    ::B C D E F G H I J K L M N O P Q R S T U V W X Y        Z (注意Z前面的大片空格,证明后续的字符串没有被再分割,而是作为一个整体)
    

    上面的例子,会将每一行分成 1,* 两个部分,因此文件的每一行会被分割成两块,一旦分割成两块后,后续哪怕有再多空格或者分隔符,都不会分割了,而是会当成一个整体字符串(这只是我个人猜测而已,但是和实际结果吻合):

  • 1 代表了第一列
  • * 时通配符,代表了后续所有的字符串(注意:依然只是一个字段)
  • 删除行前空白:

    @echo off
    REM 删除空行并且删除行首的空格或制表符
    for /f "tokens=*" %%i in (a.txt) do (
    	echo,%%i
    pause
    

    eol 用来指定一个字符,然后 for /f 处理一行文本时,如果文本以这个字符开头,就会忽略这一行

    @echo off
    :: 默认忽略分号开头的行, 它会读取 a.txt 的内容,遇到分号开头的行,就会略过
    for /f %%i in (a.txt) do (
        echo,%%i
    pause
    

    指定忽略以 # 开头的行:

    @echo off
    REM 忽略指定字符开头的行
    for /f "eol=#" %%i in (a.txt) do (
    	echo,%%i
    pause
    

    用来跳过几行。

    @echo off
    REM 跳过一行
    for /f "skip=1" %%i in (a.txt) do (
        echo,%%i
    pause
    
    usebackq

    usebackq 可以将双引号的内容作为文件,并且它会将单引号看作字符串(不使用usebackq的情况,单引号里面代表命令),将反引号看作命令。

    @echo off
    REM 默认把双引号里面的内容当做字符串处理
    for /f "tokens=2" %%i in ("a 1.txt") do (
    	echo,%%i
    pause
    

    譬如文件包含空格,需要加引号:

    @echo off
    REM 正确处理文件名包含空格的情况
    for /f "usebackq tokens=2" %%i in ("a 1.txt") do (
    	echo,%%i
    pause
    

    处理命令输出

    for /f 这种语句中,我们将命令放在单引号中,for /f 会自动将单引号的内容,作为命令进行执行并处理它的输出。

    @echo off
    :: 括号里的单引号有特殊含义,代表里面是命令; ^| 用来转义管道符
    for /f "delims=" %%i in ('dir /b *.txt ^| findstr "[0-9]"') do (
    	echo,%%i
    pause
    :: ^= 转义等号
    for /f "delims=" %%i in ('wmic LogicalDisk where DriveType^="3" get DeviceID') do (
    	echo,%%i
    pause
    :: ^, 转义逗号
    for /f "delims=" %%i in ('wmic NicConfig get IPAddress^, MACAddress /value') do (
    	echo,%%i
    pause
    :: ^> 转义重定向符号
    for /f "delims=" %%i in ('dir /b /s /a-d "*.jpg" 2^>nul') do (
    	echo %%i
    pause
    

    语法:GOTO label, 用来跳转到 label 指定的代码处。

    @echo off
    :: begin 是一个标签,标签的定义规则是以 : 开头
    :begin
    set /a var+=1
    echo %var%
    :: 当 var 变量值 小于等于 3,跳转到 begin 自身(类似递归)
    if %var% leq 3 goto begin
    pause
    

    标签并不是一个函数,它只是用来标记一个代码段

    goto 后面的 label 可以带: 也可以不带。如:goto :begin 等同于 goto begin,但是建议带上。

    goto :eof 用来退出脚本。eofend of file 的意思,相当于执行到程序末尾,从而变相退出脚本。

    三种方式退出程序:

  • exit /b
  • goto :eof
  • goto :eof 并不是真的退出了脚本,而是执行到文件的末尾,变相的退出程序。

    exit 彻底退出脚本。

    exit /b 仅退出当前的批处理脚本。

    譬如编写一个 test.bat 文件,在里面分别写上三种退出方式,然后我们开启一个命令行窗口,用命令行来执行这个脚本(不是直接双击运行):C:\Users\wztshine\Desktop>test.bat

  • goto :eof 会退出脚本,但是我们的命令行窗口还在。
  • exit /b 会退出批处理脚本,命令行窗口还在。
  • exit 会将我们的命令行窗口一起关闭。
  • start

    启动另一个窗口运行指定的程序或命令。

    START ["title"] [/Dpath] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED] [/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL] [/WAIT] [/B] [command/program] [parameters]
    
  • "title" 在窗口标题栏中显示的标题。
  • path 起始目录
  • I 新环境是传递给 cmd.exe 的原始环境,而不是当前环境
  • MIN 开始时窗口最小化
  • MAX 开始时窗口最大化
  • SEPARATE 在分开的空间内开始 16 位 Windows 程序
  • SHARED 在分共享的空间内开始 16 位 Windows 程序
  • LOW 在 IDLE 优先级类别开始应用程序低优先级
  • NORMAL 在 NORMAL 优先级类别开始应用程序 一般优先级
  • HIGH 在 HIGH 优先级类别开始应用程序高优先级
  • REALTIME 在 REALTIME 优先级类别开始应用程序实时优先级
  • ABOVENORMAL 在 ABOVENORMAL 优先级类别开始应用程序 超出常规优先级
  • BELOWNORMAL 在 BELOWNORMAL 优先级类别开始应用程序 低出常规优先级
  • WAIT 启动应用程序并等候它结束
  • B 在不创建新窗口的情况下开始应用程序。 除非启动 ^C 处理,否 则该应用程序会忽略 ^C 处理;^Break 是唯一可以中断该应用程序的方式
  • command/program
  • 如果是内部 cmd 命令或批文件,那么该命令处理器是用 /K 命令行开关运行 cmd.exe 的。 如:start cmd /K dir 即保留新开的cmd窗口, /c 可以关闭新开的窗口
  • 如果不是内部 cmd 命令或批文件,则是一个程序,并作为窗口应用程序或控制台应用程序运行。
  • parameters 传递给前面命令或程序的参数
  • start 可以打开程序,路径,文件,网址等,譬如:

    @echo off
    start D:\Tencent\QQ\Bin\QQ.exe
    start C:\批处理教程.txt
    ::打开 E 盘
    start E:
    start www.baidu.com
    

    带有空格的文件夹:

    start "" "C:\Users\wztshine\Desktop\s d"
    

    当打开带有空格的文件夹或文件时,需要加上双引号,并且前面必须使用 title 参数,否则这个文件夹会被当成 title 参数。因此我们前面加上了一个空白的 "" 来作为 title。

    call 命令来调用一个程序段或者另一个批处理文件。调用完成后,程序会从之前调用的地方继续执行(就像 python 或者 java 等调用函数一样,函数执行完毕后,会回到之前调用它的地方继续执行)

    call [[Drive:][Path] FileName [BatchParameters]] [:Label [Arguments]]
    

    参数说明:

  • [Drive:][Path] 指定要调用的批处理程序的位置和名称。
  • FileName 参数必须有 .bat.cmd 扩展名。
  • BatchParameters 指定批处理程序所需的任何命令行信息,包括命令行选项、文件名、 批处理参数(即从 %0%9)或变量(例如,%baud%)。
  • call: Label Arguments
  • 调用本文件内命令段,相当于调用本文件内的函数。被调用的命令段以标签:label 开头,以 goto:eof 结尾,调用完后程序会回到原来的地方继续按顺序执行下去。假如被调用命令段(子程序)以 exit 结尾,那么调用完子程序后,程序就直接退出。被调用的函数应该以 goto :eof 作为结尾来表示函数到此截至,否则后续所有的命令都会被当作函数的一部分执行。
  • 创建代码段

    我们可以使用 :name 的方式,来创建一个名为 name 的代码段,一个代码段仅仅是用来标记一段代码,它并不是一个函数,它不需要调用就能执行,因为它和普通代码一样,只是我们给它加了个标记而已:

    @echo off
    :: 这个代码段,没有设置结尾
    :func
        echo hello
    echo world
    pause
    
    hello
    world
    请按任意键继续. . .
    

    goto :eof 来设置代码段的结尾,我们需要手动设置它来让这个代码段截止:

    :func
        echo hello
        pause
        goto :eof
        :: func 截至到这里,后续的命令便不会继续执行了
    echo world
    pause
    

    注意:后续会用 函数 一词来形容这种代码段,但是注意:它并不是真的其他编程语言中的函数。

    调用其他批处理文件

    我们可以直接调用其他批处理程序:

    CALL "C:\Documents and Settings\Administrator\桌面\圆周率.bat"
    

    当然,后面也可以加参数:

    call "c:\test.bat" 1 2 3 
    

    调用本文件的代码段

    @echo off
    call :func
    pause
    :func
      echo hello
      goto :eof
    

    调用函数并传参

    我们可以给函数传参:

    call :func arg1 arg2 arg3 ..
    

    然后在函数中,可以通过 %0 %1 %2 ... 等来接受参数。注意:%0 代表了 函数或者 可执行程序路径 本身。

    @echo off
    call :func 1 2 3
    pause
    :func
      echo %0 %1 %2 %3
      goto :eof
    
    :func 1 2 3              # 输出了 :func 这是 %0 的值
    请按任意键继续. .
    

    变相获取返回值

    @echo off
    :: 传递两个参数
    call :sub return Hello
    echo returned: %return%
    pause>nul
    :: 我们将第二个变量赋值给第一个变量:return=Hello
    set %1=%2
    

    使用 SETLOCALENDLOCAL 来手动声明局部变量。其他变量都是全局变量。

    returned: Hello
    

    另一个求和的例子:

    @echo off
    set sum=0
    call :sub sum 10 20 35
    echo 数据求和结果: %sum%
    pause>nul
    goto :eof
    set /a %1=%1+%2
    :: shift /2 的作用是:从第二参数开始,向左移动一位:将 %3 移位到 %2,将 %4 移位到 %3,等等;并且不影响 %0 和 %1。
    shift /2
    if not "%2"=="" goto sub
    

    分析一下:

    第二行,我们设置了 sum=0

    第三行我们将 sum 10 20 35 传递给 :sub 代码段,注意这里的 sum 是字符串,并非变量 %sum%

    :sub 中,将参数带入 set /a %1=%1+%2, 得到:set /a sum=sum+10 ,还记得之前说过:set 声明变量时,等号右侧的变量可以忽略 % 吗?因此这里右侧的 sum 其实是全局变量 %sum%,即:set /a sum=0+10

    shift 移动变量,然后递归 ...

    shift

    shift 可以向左移动参数。该命令行 开关告诉命令从第 n 个参数开始移位;n 介于零和八之间。例如: SHIFT /2 会将 %3 移位到 %2,将 %4 移位到 %3...,并且此时不影响 %0 和 %1

    shift [/n]
    

    之前说过的求和例子:

    @echo off
    call :sub sum 1 2 3 4 5 6 7 8 9
    echo result: %sum%
    pause>nul
    set /a %1=%1+%2
    :: 从第二个参数开始,向左移动
    shift /2
    :: 判断参数是否为空,否则继续
    if not "%2"=="" goto sub
    

    title

    设置命令行窗口名称:

    title BAT
    

    color

    设置命令行窗口的背景色和前景颜色(前景色即文字颜色)

    它的参数是两个 16 进制数字(数字之间没有空格

    支持的颜色如下:

    0 = 黑色       8 = 灰色
    1 = 蓝色       9 = 淡蓝色
    2 = 绿色       A = 淡绿色
    3 = 浅绿色     B = 淡浅绿色
    4 = 红色       C = 淡红色
    5 = 紫色       D = 淡紫色
    6 = 黄色       E = 淡黄色
    7 = 白色       F = 亮白色
    
    color F5
    

    注意:两个颜色不能一样。

    它有两个主要作用:

  • 设置 cmd 窗口的大小
  • 设置代码页
  • 设置窗口大小

    mode con cols=113 lines=15 
    

    cols 指定宽度

    lines 指定高度

    设置代码页

    mode con cp select=936
    

    将控制台显示语言设置成中文(936), 437 代表英文

    C:\Users\wztshine>mode con cp select=437
    Status for device CON:
    ----------------------
        Lines:          200
        Columns:        88
        Keyboard rate:  31
        Keyboard delay: 1
        Code page:      437
    C:\Users\wztshine>mode con cp select=936
    设备状态 CON:
    ---------
        行:        200
        列:       88
        键盘速度:   31
        键盘延迟:  1
        代码页:     936
    

    date / time

    time 命令显示和设置当前系统时间(时分秒), /t 选项可以仅显示时间(时分)而不设置时间。

    date 命令显示和设置当前系统日期, /t 选项可以仅显示日期而不设置日期。

    C:\Users\wztshine>time
    当前时间: 16:54:28.20
    输入新时间:
    C:\Users\wztshine>time /t
    16:54
    C:\Users\wztshine>date
    当前日期: 2022/05/20 周五
    输入新日期: (年月日)
    C:\Users\wztshine>date /t
    2022/05/20 周五
    

    修改时间:

    time 09           # 修改当前时间为 09:00 整
    time 09:13        # 修改当前时间为 09:13:00 整
    time 09:13:30     # 修改当前时间为 09:13:13.00 整
    time 09:13:30.25  # 修改当前时间为 09:13:30.25 精确修改
    

    修改日期:

    date 2013-10-1
    date 2013/10/3
    date 2013/09-25 
    

    vol 可以查看磁盘卷标和序列号(如果存在)。所谓卷标,例如 软件(D:), “D:” 是磁盘名,“软件” 是卷标。

    C:\Users\wztshine>vol c:
     驱动器 C 中的卷没有标签。
     卷的序列号是 284A-C138
    C:\Users\wztshine>vol d:
     驱动器 D 中的卷是 本地磁盘
     卷的序列号是 0007-6A37
    

    LABEL

    创建、更改或删除磁盘的卷标。

    LABEL [drive:][label] 
    

    drive: 指定驱动器

    label : 指定卷标

    label D:Software
    

    ATTRIB

    显示或更改文件属性。

    ATTRIB [+R | -R] [+A | -A ] [+S | -S] [+H | -H] [[drive:] [path] filename] [/S [/D]] 
    

    +,- 代表添加或删除某个属性

  • R 只读文件属性。
  • A 存档文件属性。
  • S 系统文件属性。
  • H 隐藏文件属性。
  • [drive:][path][filename]指定要处理的文件路径。
  • /S 处理当前文件夹及其子文件夹中的匹配文件。
  • /D 也处理文件夹。
  • 注意:如果将文件属性修改为系统属性后,将无法对属性再进行修改, 所以 -s 没用!

    默认输出当前目录下所有文件的属性(不包含文件夹):

    C:\Users\wztshine\Desktop\sd>attrib
    A                    C:\Users\wztshine\Desktop\sd\t.txt
    A                    C:\Users\wztshine\Desktop\sd\xx.bat
    

    指定文件夹:

    C:\Users\wztshine\Desktop\sd>attrib b   # 指定 b 文件夹
                         C:\Users\wztshine\Desktop\sd\b
    

    将文件夹设置隐藏:

    C:\Users\wztshine\Desktop\sd>attrib +h b  # 将 b 文件夹设置隐藏
    

    del 删除的东西,不会到回收站DELERASE 命令是一样的,都是用来删除一个或多个文件,支持通配符删除。

    DEL [/P] [/F] [/S] [/Q] [/A[[:]attributes]] names
    
  • /P 删除每一个文件之前提示确认。
  • /F 强制删除只读文件。
  • /S 从所有子目录删除指定文件(会遍历子文件夹,自动找到指定文件名的文件)。
  • /Q 安静模式。直接删除文件,不需要用户确认
  • /A 根据属性选择要删除的文件。
  • R 只读文件
  • S 系统文件
  • H 隐藏文件
  • A 存档文件
  • - 表示“否”的前缀, 如 -H 代表不是隐藏文件。
  • /-Y: 如果目录有同名文件,出现提示对话,让用户确认

    待移动的文件可以是 绝对路径,也可以是相对路径,也可以用通配符 *, ?

    destination 是一个目录,这个目录必须事先存在(绝对路径和相对路径都可以)

    md folder
    move /y x.txt folder
    move /y *.txt folder
    

    移动文件夹

    将文件夹 b 移动到文件夹 a:

    C:\Users\wztshine\Desktop\sd>move b a
    移动了         1 个目录。
    

    如果移动前,目的文件夹 a 内已经包含了同名文件夹 b,则可能无法移动,提示拒绝访问。

    move 不仅可以移动文件或文件夹,还可以重命名他们:

    move t.txt b\a.txt  # 将 t.txt 移动到 b 文件夹内,并重命名为 a.txt
    

    将一份或多份文件复制到另一个位置。copy 不可以复制文件夹,复制文件夹应该用 xcopy 命令。 copy 不可以复制具有隐藏、系统属性的文件,要复制这些文件,要先用 attrib 去除文件属性或者改用 xcopy 命令。

    copy 支持通配符 * ?

    COPY [/D] [/V] [/N] [/Y | /-Y] [/Z] [/L] [/A | /B ] source [/A | /B] [+ source [/A | /B] [+ ...]] [destination [/A | /B]]
    
  • source 指定要复制的文件(绝对或相对路径)
  • /A 表示以ASCII 文本复制文件。
  • /B 表示以二进位的方式复制文件。
  • /D 允许解密要创建的目标文件
  • destination 为新文件指定目录和文件名(绝对或相对路径)
  • /V 验证新文件写入是否正确。
  • /N 复制带有非 8dot3 名称的文件时, 尽可能使用短文件名。
  • /Y 不要提示,直接覆盖已存在的文件
  • 复制到文件夹

    :: 目的地可以是一个文件夹
    copy D:\test.txt D:\test\
    :: 通配符,复制所有 txt 文件
    copy D:\*.txt D:\test\
    

    复制到文件

    复制时,可以指定复制后的文件名

    :: 复制文件,注意复制时文件名可以改变
    copy D:\test.txt D:\abc.txt
    

    合并多个文件

    copy 还可以合并多个文件,并将合并结果保存下来

    :: 以二进制的方式,合并三个 txt 文件的内容,到 all.txt
    copy /b 1.txt+2.txt+3.txt all.txt
    copy *.txt all.txt
    

    XCOPY

    复制文件或目录树。 copy 是内部命令,xcopy 是外部命令。

    XCOPY source [destination] [/A | /M] [/D[:date]] [/P] [/S [/E]] [/V] [/W] [/C] [/I] [/Q] [/F] [/L] [/G] [/H] [/R] [/T] [/U] [/K] [/N] [/O] [/X] [/Y] [/-Y] [/Z] [/EXCLUDE:file1[+file2][+file3]...] 
    

    source 指定要复制的文件。

    destination 指定新文件的位置或名称。

    /A 只复制有存档属性集的文件,但不改变属性。

    /M 只复制有存档属性集的文件,并关闭存档属性。

    /D:m-d-y 复制在指定日期或指定日期以后更改的文件。如果没有提供日期,只复制那些源时间比目标时间新的文件。

    /EXCLUDE:file1[+file2][+file3]... 指定含有字符串的文件列 表。每一个字符串必须在文件的单独行中。如果有任何字符串与要被 复制的文件的绝对路径相符,那个文件将不会得到复制。例如,指定 如 \obj\ 或 .obj 的字符串会排除目录 obj 下面的所有文件或带 有.obj 扩展名的文件。

    /P 创建每个目标文件前提示

    /S 复制目录和子目录(如果目录是空的,则不会复制)。

    /E 复制目录和子目录,包括空的。与 /S /E 相同。可 以用来修改 /T。

    /V 验证每个新文件。

    /W 提示您在复制前按键。

    /C 即使有错误,也继续复制。

    /I 如果目标不存在,又在复制一个以上的文件,则假 定目标一定是一个目录。

    /Q 复制时不显示文件名。

    /F 复制时显示完整的源和目标文件名。

    /L 显示要复制的文件。

    /G 允许将没有经过加密的文件复制到不支持加密的目标。

    /H 也复制隐藏和系统文件。

    /R 覆盖只读文件。

    /T 创建目录结构,但不复制文件。不包括空目录或子目录。/T /E 包括空目录和子目录。

    /U 只复制已经存在于目标中的文件。

    /K 复制属性。一般的 Xcopy 会重置只读属性。

    /N 用生成的短名复制。

    /O 复制文件所有权和 ACL 信息。

    /X 复制文件审核设置(隐含 /O)。

    /Y 复制文件审核设置(隐含 /O)。现存目标文件。

    /-Y 导致提示以确认改写一个 现存目标文件。

    /Z 用重新启动模式复制网络文件。

    copy C:\*.* D:\   # 只会复制 C 盘的文件
    xcopy C:\*.* D:\  # 会复制 C 盘所有内容:文件,文件夹,子文件夹
    

    复制所有内容(包括空的文件夹):

    xcopy F:\ G:\abc\ /e /s /h /y
    

    复制特定日期之后的内容:

    :: 复制 Rawdata 目录中 1993 年 12 月 29 日以及以后更改的文件更新到 Reports 目录中的文件。
    xcopy D:\rawdata E:\reports /d:12-29-1993
    :: 仅复制较新的文件
    xcopy D:\rawdata E:\reports /d
    

    复制一个文件夹时,它只会复制文件夹下的内容,而不是将这个文件夹复制到某处:

    :: 它只会将 folder1 下的所有内容复制到 folder2 中,不会在 folder2 中创建一个 folder1
    xcopy folder1 folder2 /s /e /h /y
    

    在文件中搜索字符串。

    FIND [/V] [/C] [/N] [/I] [/OFF[LINE]] "string" [[drive:][path]filename[ ...]] 
    

    参数说明:

  • /V 显示不包含指定字符串的行。
  • /C 显示符合条件的行数。
  • /N 显示每一行时,同时显示行号
  • /I 搜索字符串时忽略大小写。
  • /OFF[LINE] 不要跳过具有脱机属性集的文件。
  • "string" 指定要搜索的文字串
  • [drive:][path]filename 指定要搜索的文件
  • 支持通配符,可以在多个文件中查找:

    @echo off
    :: 显示不包含 abc 的行,并忽略大小写
    find /v /i "abc" D:\*.txt
    pause
    

    现有 a.txt:

    @echo off
    echo 仅显示带 1 的行
    find /i "1" a.txt
    echo 显示每一行的行号
    find /i /n "1" a.txt
    echo 显示不包含 1 的行
    find /i /v "1" a.txt
    echo 显示有多少行带 1
    find /i /c "1"  a.txt
    echo 显示不带 1 有多少行
    find /i /c /v "1"  a.txt
    pause
    

    type 搭配,先读取文件,然后过滤包含 '2' 的行:

    @echo off
    mode con cols=100
    type a.txt | find /n "2"
    pause
    

    FINDSTR

    在文件中寻找字符串

    FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/F:file] [/C:string] [/G:file] [/D:dir list] [/A:color attributes] [/OFF[LINE]] strings [[drive:][path]filename[ ...]] 
    
  • /B 在一行的开始配对模式。
  • /E 在一行的结尾配对模式。
  • /L 按字使用搜索字符串。
  • /R 将搜索字符串作为一般表达式使用。
  • /S 在当前目录和所有子目录中搜索匹配文件。有了这个参数,就不可以指定搜索路径了,否则出错。
  • /I 指定搜索不分大小写。
  • /X 打印完全匹配的行。
  • /V 只打印不包含匹配的行。
  • /N 在匹配的每行前打印行数。
  • /M 如果文件含有匹配项,只打印其文件名。
  • /O 在每个匹配行前打印字符偏移量。
  • /P 忽略有不可打印字符的文件。
  • /OFF[LINE] 不跳过带有脱机属性集的文件。
  • /A:attr 指定有十六进位数字的颜色属性。请见 "color /?"
  • /F:file 从指定文件读文件列表 (/ 代表控制台)。
  • /C:string 使用指定字符串作为文字搜索字符串。
  • /G:file 从指定的文件获得搜索字符串。 (/ 代表控制台)。
  • /D:dir 查找以分号为分隔符的目录列表 strings 要查找的文字。
  •