bat详解

bat批处理脚本

cmd命令官方文档

https://blog.csdn.net/qq_36838191/article/details/83046599

https://blog.csdn.net/spw55381155/article/details/90264344

https://blog.csdn.net/qq_37858386/article/details/103048256


bat基本信息

  • bat脚本实际就是批处理文件,文件的每一行都是DOS命令
  • DOS命令是磁盘操作系统(Disk Operating System),通过指令操作计算机
  • 脚本对大小写不敏感
  • 文件的后缀名为.bat或.cmd

系统变量(参数)

系统变量的参数可以在bat脚本中直接引用

  • 打开cmd输入set回车可以得到系统变量参数列表

    set
    
  • 以下列一些常用系统参数

    • 当前计算机的名称

      %COMPUTERNAME%
      
    • 用户个人文件夹的完整路径

      %USERPROFILE%
      
    • Windows系统目录

      %WINDIR%
      

参数传递

  • 执行bat脚本时,可以从外部传入参数,从脚本里面获取参数

    但这种方式不能直接执行test.bat脚本,需要用cmd命令行执行该脚本,并传入参数

    test.bat $arg1 $arg2 $arg3...
    
  • 外部传入的参数,在脚本内部使用%0到%9来接收

    其中%0代表bat脚本自身绝对路径(路径+名字+后缀)

    %1到%9分别对应外部传入的第一到第九个参数

    echo %0
    echo %1
    echo %2
    ...
    

特殊变量扩展表达式

  • 获取当前bat脚本的父路径

    由%0扩展而来,d等于driver,提取驱动器号(盘符),p等于path,提取路径部分

    echo %~dp0
    
  • 获取当前bat脚本名字(不包含扩展名),~n等于name,提取名字

    echo %~n0
    
  • 获取当前bat脚本后缀,~x等于extension,提取扩展名

    echo %~x0
    
  • 获取当前bat脚本名字+后缀,上面两个拼起来即可

    echo %~nx0
    

cmd批处理基本语法命令

只列举了最基础的用法,很多命令都有参数但这里并没有解释到,需要用时可问ai

写脚本前的一些注意事项

  • 字符串带有空格或标点符号,要加双引号,如set “a=abcd,efg”,不能是set a=“abcd,efg”
  • 如果是后者,引用变量会附带双引号,而前者引用则不会
  • 当前目录下不要用./而是要用%~dp0
  • 几个命令杂糅在一起的,尽量使用括号括起来或者换行,cmd有可能会识别不出来
  • 实测for和if命令之间少了空格会导致运行闪退,所以该有空格地方不能漏,不然难排查

echo和@

  • echo有两个功能,一是输出信息到控制台,二是控制脚本内写的命令不在控制台输出(回显)
  • @代表脚本当前行不在控制台输出
  • @echo off两者搭配可以使脚本命令全部不输出到控制台,因此大多数bat脚本首行都写这句
# 输出信息
echo helloworld

# 控制脚本命令不在控制台输出(但本身当前行会被输出)
echo off

#控制脚本命令不在控制台输出且当前行也不输出
@echo off

rem和::

  • 两者都是起到注释的作用,冒号是两个并且是英文,哪个用的习惯就用哪个
::这是一个注释
rem 这也是一个注释
...

goto和:

  • :label 用来标记位置,名字可随便起(label只是代指标签),但最好有意义

  • goto label,去到指定标签位置执行标签下的命令(label只是代指标签)

  • 两者结合起来其实就是流程控制,一般会配合if一起使用

  • 但是自己研究时发现,标签大致分为两个作用:

    1. 用于流程控制,但这个可以使用if代替
  1. 用于循环,但这个也可以使用for代替
  • 下面举例上面写到的两个作用:
# 流程控制
@echo off
::支持utf-8编码格式,cma默认是gbk格式
chcp 65001 > nul

::这里踩过坑,等号左右不能有空格,否则运行就闪退
set /p a=输入1或2:
if %a%==1 goto a_1
if %a%==2 goto a_2

:a_1
echo a=1
::这里不设结束标签会把a_2标签一起执行,起不到流程控制作用
goto a_end

:a_2
echo a=2
goto a_end

echo -------------
:a_end
echo 该流程结束,继续执行下面代码
pause
# 循环
@echo off
chcp 65001 > nul

set a=1
:for_start
::变量自增或自减方式需要加上/a参数
set /a a+=1
echo %a%
if %a% lss 5 goto for_start

echo 该流程结束,继续执行下面代码
pause

pause

  • 暂停脚本的运行,需要在cmd窗口中按任意键才会继续执行脚本或结束脚本
  • 一般用于暂停查看信息,如果不暂停,脚本执行完后cmd窗口会关闭看不到信息
echo helloworld
pause

call

  • 调用别的bat脚本文件
  • 如不加call调用,会导致执行完子脚本后,无法返回父脚本执行后续命令
  • 可能存在需求:调用子脚本后,需要获取子脚本返回内容作为父脚本变量使用
  • 该情况需要配合for一起才能实现,后续讲到for时会体现,这里先不说
# 调用当前路径下的xxx.bat脚本
call %~dp0\xxx.bat

# 调用当前脚本并传递参数
call %~dp0\xxx.bat arg1 arg2...

start

  • 调用外部程序,bat脚本也可以,加/min参数可以使应用打开时最小化
start d:\xxx\xxx.exe

#打开程序时最小化
start /min %~dp0/xxx.bat

choice

  • 该命令只接收字符列表中的单个字符,控制严格,而set /p可以接收任意文本输入
  • 所以在接收用户输入的场景时,choice用的不多,更多用的set /p,后续会写到set命令

set

  • 用于定义变量,变量的引用使用%var%包起来
  • /p 参数(开关)可以接收用户输入并且赋值给变量
  • /a 参数(开关)可以给变量赋值同时进行计算(自增、加减乘除、取余都可)取余用%%
  • set /a里面的数都必须是整数,不支持浮点数运算
set /p content=输入1或2
echo %content%

set /a num+=1
echo %num%

if

  • if判断大于小于相等

    格式:if [not] xx==xx 命令

    lss-小于(less),leq-小于等于(less equal),gtr-大于(great),geq-大于等于(great equal)

    set a=1
    if %a%==1 echo a=1
    # >在cmd中是重定向的作用,使用^可以转义
    if %a% gtr 0 echo a^>0
    if %a% lss 2 echo a^<2
    set b=abc
    if not %b%==abc echo %b%=abc
    
  • if判断是否存在

  • 格式:if [not] exist [路径]文件名 命令

    set a=1
    if exist %~dp0\xxx.bat set /a a+=2
    if not exist d:\xxx.py set /a a-=5
    echo %a%
    
  • if-else结构

    带有else结构,条件后执行的命令用括号包起来,否则cmd识别不了

    set c=-5
    
    # 一行写完
    if %c% gtr 0 (echo c^>0) else (echo c^<0)
    
    # 多行,但是要保证右括号和else在同一行,否则cmd报错说else不是内部或外部命令
    # 适用于条件命令有多行
    if %c% lss -10 (
    echo c^<-10
    )else if %c% lss 0 (
    echo c^<0
    )else (
    echo c^>0
    )
    
    # 第二种多行,这种情况适用于条件和命令在一行写完,使用^换行连接,不加^会报错
    if %c% lss -10 (echo c^<-10)^
    else if %c% lss 0 (echo c^<0)^
    else (echo c^>0)
    
  • 判断程序返回值

    格式:if [not] errorlevel <数字> 命令

    几乎所有的命令在执行后都会返回一个errorLevel,是用来反映该命令执行的状态

    所以判断返回值,前面必须有一条dos命令,否则errorLevel无意义

    命令执行成功后会返回0,如果不是0说明执行失败

    errorlevel本身是一个变量,可以通过%errorlevel%引用输出查看他的值

    这种方式了解即可,因为可以通过逻辑操作符来模拟三元运算符的效果替代if结构

    在下面特殊符号章节会举例子说明,会比这里的代码写的更优雅简洁

    # 切换到存在路径
    cd c:
    # 可以直接引用输出
    echo errorlevel=%errorlevel%
    if errorlevel 0 echo command is success
    
    
    # 切换到不存在路径
    cd f:\aaa
    if errorlevel 1 echo command is fail
    

for

  • 基本格式

    for /参数 [选项] %%变量 in (set) do 命令 [命令参数]

    # 遍历输出字母
    for %%i in (a,b,c,d,e) do echo %%i
    
  • 四个参数,/d /l /r /f

    /d支持set集合中使用通配符(?和*)

    /l支持以增量形式表示一个数字序列

    /r支持递归查找指定目录下符合条件的文件,默认识别通配符,且要加路径参数

    /f支持解析字符串、命令、文件(一般就是一次性读取命令返回值和文件内容)

    # 把d盘下所有目录和文件都打印
    for /d %%i in (d:\*) do echo %%i
    # 把d盘下只有三个字符的目录和文件打印
    for /d %%i in (d:\???) do echo %%i
    
    # 输出1-10序列
    for /l %%i in (1,1,10) do echo %%i
    # 打开10个cmd窗口
    for /l %%i in (1,1,10) do start cmd
    
    # 递归查找d盘下以exe结尾的文件
    # /r参数需要添加路径(盘符),set集合里面字符串相当于过滤
    for /r d:\ %%i in (*.exe) do echo %%i
    # 递归查找当前bat文件目录下的所有文件
    for /r %~dp0  %%i in (*) do echo %%i
    # 递归查找某个盘中指定名字的文件
    for /r e:\ %%i in (testcase.xlsx) do (if exist %%i echo %%i)
    
    #/f参数这里先不举例,需要配合常用选项使用,先了解下面选项意思,然后在下面举例
    
  • 常用选项

    for /f基本解释:会将空格制表符视为分隔符,按照分隔符切割成多个字段token(有点像linux中的awk),如果被空格分为多个字段,只会输出第一个字段,第二个字段不显示,所以一般都要指定分隔符delims来忽略空格的影响

    eol(end of line)结束行标志,跳过指定字符串开始的行,只能一个字符,多于一个报错

    # test.txt内容
    # 这是一个注释
    这是正文
    111223344
    -------------------
    # 结束
    
    # eol例子,打印某个文件内容,#开头的文本不输出
    for /f "eol=#" %%i in (%~dp0\test.txt) do echo %%i
    

    delims(delimiters)分隔符,指定分隔符,可忽略空格切割多个字段的影响,整行输出

    # test.txt内容
    test qqqwwee 666666
    abc-def-ghjkl-mnopq
    // oh-are you ok
    hey bro,you're so good today
    
    # delims忽略空格,输出整行(想看被分割效果,去掉delims再执行bat即可)
    for /f "delims=" %%i in (%~dp0\test.txt) do echo %%i
    
    # delims指定分隔符,分割后需要token字段做二次处理,否则只会显示第一个字段
    for /f "delims=-" %%i in (%~dp0\test.txt) do echo %%i
    

    skip,跳过文件行数

    # skip跳过前两行,并且忽略空格因素,文本使用上面内容
    for /f "skip=2 delims=" %%i in (%~dp0\test.txt) do echo %%i
    

    tokens(标记),分割字段后可以指定显示第几字段的内容,支持通配符

    分割后多了几个字段就要多加几个变量接收,%%i只会接受第一个字段

    可能会存在分割后变量接受为空的情况(不是每行都能分割好几个字段),需要后续if做处理

    # test.txt内容
    test-qqqwwee-666666
    abc-def-ghjkl-mnopq
    // oh-are you ok
    hey bro,you're so good today
    add fifth line
    
    # 使用tokens显示全部字段
    for /f "tokens=*" %%i in (%~dp0\test.txt) do echo %%i
    
    # 使用空格作为分隔符,只显示2和4字段
    for /f "tokens=2,4" %%i in (%~dp0\test.txt) do (
    echo two field ====%%i 
    echo four field ====%%j
    )
    
    # 使用-作为分隔符,且忽略空格分割,显示除第2字段以外所有字段
    # 1字段使用i变量接收,3字段使用j接收,剩余的字段*使用k接收(j不能同时接收3*)
    for /f "delims=- tokens=1,3*" %%i in (%~dp0\test.txt) do (
    echo two field ====%%i 
    echo three field ====%%j
    echo other field ==== %%k
    )
    
    # 使用-作为分隔符,且忽略空格分割,显示第2到第4字段
    for /f "delims=- tokens=2-4" %%i in (%~dp0\test.txt) do (
    echo two field ====%%i 
    echo three field ====%%j
    echo four field ==== %%k
    )
    
  • set集合

    set集合中可以包含多种类型,这里列举几种常见的

    # 文件
    for /d %%i in (*.txt) do echo %%i
    
    # 字符串
    for /r d:\ %%i in (*test*) do echo %%i
    
    # 数字序列
    for /l %%i in (1,1,5) do echo %%i
    
    # 命令(单引号括起来),字符串(双引号括起来)
    for /f %%i in ('adb devices') do echo %%i
    for /f %%i in ("str_content") do echo %%i
    
  • for循环一些注意小事项或实用小技巧

    1. 实际中for循环使用/f参数频率最高,特别是忽略空格,都要加上delims

    2. delims和tokens=*实现的效果是一样的

    3. do后面命令有多行,需要换行写,挤在一行会出问题

    4. set集合里面是命令,需要使用单引号括起来,双引号不行

    5. for命令中不能实现传入一个字符串,把每个字符遍历出来,这个需要goto实现

    6. 调用子脚本并且获取其输出的值,可作为父脚本变量使用,可以使用for实现

      # 子脚本child.bat 最后会echo qwer1234
      ...
      ...
      echo qwer1234
      
      # 父脚本调用子脚本并获取输出作为变量
      for /f "delims=" %%i in ('call %~dp0\child.bat') do set value=%%i
      

setlocal

  • cmd有如下机制:

    在逻辑执行前就把变量赋值完成,无论当前行(循环体)怎么捣鼓变量,还是之前给定的值。因为cmd是先赋值后再执行变量相关逻辑,直到下一行的命令开始,前面捣鼓变量的值才会被更新(可以简单理解为命令行中变量的改变,要到下一条命令才会更新)

    本质上其实就是变量赋值的顺序是在逻辑前还是逻辑后

    举例同一命令行或循环体内变量改变

    # a改变值,在同一行输出,在a改变变量前,就已经被赋值a=1
    # 所以第一个a的值为1,第二个a的值为6
    set /a a=1
    set /a a+=5 & echo %a%
    echo ---%a%---
    
    # a改变值和输出都在同一个循环体内,在循环执行前就被赋值a=1,
    # 所以循环输出的a五次都是1,而循环体外的是循环执行后a的值为16
    set /a a=1
    for /l %%i in (1,1,5) do (
    set /a a+=%%i
    echo %a%
    )
    echo ---%a%---
    
  • setlocal动态更新变量

    大概原理:引用变量时,不会立即赋值之前给定的值,而是等程序逻辑走完,变量的值已经被更新过,此时再引用变量,就会赋值到最新的值

    # 开启setlocal
    setlocal EnableDelayedExpansion
    # 关闭setlocal
    endlocal
    # 变量不再使用%var%而是!var!
    set a=1
    echo !a!
    

    上面例子使用setlocal改动

    setlocal EnableDelayedExpansion
    # 两次a的结果都是6
    set /a a=1
    set /a a+=5 & echo !a!
    echo ---!a!---
    
    # 每次输出的b都是叠加i变量的值,不再是输出1
    set /a b=1
    for /l %%i in (1,1,5) do (
    set /a b+=%%i
    echo !b!
    )
    echo ---!b!---
    endlocal
    
  • setlocal嵌套变量引用

    如果变量里面嵌套变量,cmd是识别不出来的,也需要用到setlocal

    # 不使用setlocal,存在多个%%,只会就近配对变成%a:%,check_str,%=%
    # 因为两个变量没有定义为空,所以最后只会输出check_str
    # 本意是想把a字符串中r字符替换为空(%%应该是内一对,外一对)
    set "a=hello,world"
    set check_str=r
    echo %a:%check_str%=%
    
    # 使用setlocal,会输出hello,wold把r去掉
    # !和%两个变量不能用反,这里涉及到变量赋值顺序,上面有提到
    # %%是先赋值再走逻辑,!!是先走逻辑再赋值
    # 在下面例子中check_str应该是先赋值,a是先走逻辑后赋值
    # 程序执行到echo那行时,其实已经变成!a:r=!,所以是可以成功去掉r的
    # 如果反过来a无论是不是替换,都已经先赋值hello,world,最后只会输出hello,world
    setlocal EnableDelayedExpansion
    set "a=hello,world"
    set check_str=r
    echo !a:%check_str%=!
    endlocal
    

字符串处理

  • 字符串截取,可以使用变量扩展的偏移量语法(与python字符串截取很像)

    基本格式:%var:~offset,length%

    offset理解为索引,从0开始,可以为负数,代表从倒数第几个开始截取

    length截取长度,可以为负数,代表截取到倒数第几个(开区间),没有填写长度为全长

    上面说的可能有点难以理解,结合下面几个例子看会比较清晰

    set "a=hello,world"
    
    # 索引为3,取5长度(lo,wo)
    # 左往右数第四个,取五个数
    echo %a:~3,5%
    
    # 索引为2,取-2长度(llo,wor)
    # 左往右数第三个,取到倒数第二个(不包含倒数第二)
    echo %a:~2,-2%
    
    # 索引为-5,取2长度(wo)
    # 右往左数第五个,取两个数
    echo %a:~-5,2%
    
    # 索引为3,取所有(lo,world)
    # 左往右数第四个,取所有直到结尾
    echo %a:~3%
    
    # 索引为-3,取所有(rld)
    # 右往左数第三个,取所有直到(右边)结尾
    echo %a:~-3%
    
  • 字符串分割

    分割并没有特别的方法,就是使用for加分隔符实现

    set "a=qwe,asd,zxc"
    for /f "delims=, tokens=1-3" %%i in (%a%) do (
    echo %%i
    echo %%j
    echo %%k
    )
    
  • 字符串替换(或去除空格)

    set "a= hello,world "
    # 替换指定字符(所有匹配的字符)
    echo %a:o=666%
    # 不需要的字符去掉(替换为空)
    echo %a:,w=%
    # 去除空格
    echo %a: =%
    
  • 字符串拼接

    set a=hello
    set b=world
    set c=%a%%b%
    
  • 字符串查找,检查字符串是否包含某个子串

    可通过子串替换后与原字符串对比看是否变化来达到目的

    set "a=hello,world"
    
    # 检查a变量中是否包含r字符
    if %a:r=%==%a% (echo %a% not contain r) else (echo %a% contain r)
    
    # 检查a变量中是否包含abc字符
    if %a:abc=%==%a% (echo %a% not contain abc) else (echo %a% contain abc)
    

    还可以通过配合findstr达到检查目的

    需要配合命令的状态码是加以判断,findstr搜索出来返回状态码为0,搜不出来返回非0

    而逻辑与&&和逻辑或||,是根据状态码执行的

    命令状态码为0代表执行成功,执行&&,非0代表执行失败,执行||

    set "a=hello,world"
    echo %a% | findstr wor>nul && echo contain || not contain
    
  • 字符串统计长度

    统计长度的思路是:每循环一次,计数器+1,字符串长度-1,然后统计出长度

    没有直接的方法可以直接实现,goto可实现,for不可实现,因为不能遍历字符串

    # goto实现统计长度
    set "a=hello,world"
    if "%a%"=="" (
    set /a num=0
    goto end
    )
    
    :add
    set /a num+=1
    set a=%a:~1%
    
    if not "%a%"=="" goto add
    
    :end
    echo %num%
    

文件操作命令

如果命令忘了参数意思,可以在cmd上输入xxx /?获取参数解释(中文)

dir

  • 显示指定目录下的文件(夹)列表,默认会展示时间,文件大小,文件名,文件总数

  • /b代表brief,简洁格式输出,只显示文件名(只有一列)

  • /w代表width,只显示文件名,并且文件名横向输出

  • /d只显示文件名,但是文件名竖向输出(多列),会比/w排列美观一些

  • 总结来说/b堆在一列输出,/w一行一行输出,/d一列一列输出,

  • 并且/w和/d会统计文件总数,而/b不会,推荐使用/d

  • /p代表page,分页显示结果,按任意键查看下一页

  • /s代表subdirectories,列出子目录下文件,同时统计文件总数

  • /o代表排序,可以指定顺序排序文件,默认是按照名字升序

  • n(name)按照名字升序,s(size)按照大小升序,d(date)按照日期升序,-反转顺序

    # 查看桌面文件,只显示文件名,一列输出完
    dir /b C:\Users\xxx\Desktop
    
    # 查看桌面文件,只显示文件名,横向输出
    dir /w C:\Users\xxx\Desktop
    
    # 查看桌面文件,只显示文件名,多列输出
    dir /d C:\Users\xxx\Desktop
    
    # 分页查看桌面文件
    dir /p C:\Users\xxx\Desktop
    
    # 列出e盘下xxx目录所有文件
    dir /s e:\xxx
    
    # 列出e盘下xxx目录所有文件,只显示文件名,并统计文件总数
    dir /s /d e:\xxx
    
    # 列出e盘下xxx目录文件,按照名字降序
    dir /o:-n e:\xxx
    
    # 列出e盘下xxx目录文件,按照大小升序
    dir /o:s e:\xxx
    
    # 列出e盘下xxx目录文件,按照日期降序
    dir /o:-d e:\xxx
    
    # 列出e盘下xxx目录文件,按照大小降序,只显示名字
    dir /d /o:-s e:\xxx
    

cd

  • 切换盘符路径,是change directory的缩写

  • /d代表drive,支持切换盘符,如果不加的话只能在当前盘符切换路径

  • 有两种方式可以切换盘符,第一种是cd /d,第二种是直接输入盘符+冒号(e:)

  • 第二种切换后还得再cd切换路径,相对来说没有第一种方便和优雅,推荐第一种

    # 当前在c盘,切换到c盘xxx\yyy路径
    cd xxx\yyy
    # 当前在c盘,切换到e盘xxx\yyy路径
    cd /d e:\xxx\yyy
    

mkdir/md

  • 两个都是创建目录(make directory)的缩写,都可以使用,功能完全相同

  • 没有参数,且可以递归创建

  • 如果递归创建中父路径不存在不会报错,会自动创建

  • 目录中已存在该名字也不会报错,会跳过本次创建

  • 简单理解:md无参数,有目录跳过,无目录创建

    # 在e:\xxx创建一个目录abc
    md e:xxx\abc
    # 在e:\xxx创建递归目录abc/def/ggg,且abc目录不存在
    md e:xxx\abc\def\ggg
    

rmdir/rd

  • 两个都是删除目录(remove directory)的缩写,都可以使用,功能完全相同

  • /q代表quiet,删除目录时不需要确认

  • /s代表subdirectories,删除子目录及文件(简单理解为删除整个文件夹)

  • 加/s参数要谨慎,会连同文件删除,是永久删除,需要确认文件都是不用可删的

  • 如果不加参数只能删除空目录,如果目录非空,需要加/s参数才能删除

    # 删除e:\xxx\yyy 其中yyy是空目录
    rd e:\xxx\yyy
    
    # 删除e:\xxx\yyy 其中yyy不是空目录,并且不需确认
    rd /s /q e:\xxx\yyy
    

copy/xcopy

  • copy可以复制一个或一组文件(使用通配符的一组文件,指定名字的多个文件不行)

  • 只有一个参数常用,/y代表yes to all,覆盖目的地文件不需要确认

  • 根据文件名是否相同来确认是否覆盖,可能两个文件是只是名字相同但内容不同,所以复制时加/y参数需要谨慎,可能会把目的路径重要文件覆盖

    # 复制d盘下xxx目录的abc.jpg文件到当前目录,且不需要确认
    copy /y d:\xxx\abc.jpg
    
    # 举例上面说的指定名字的多个文件,下面是错误示范!
    # 复制d盘下xxx目录的abc.jpg文件,e盘下的yyy目录test.py文件到c盘zzz目录
    copy d:\xxx\abc.jpg e:\yyy\test.py c:\zzz
    # 如果是复制指定的文件,并且是多个的,需要分别执行两条copy命令
    copy d:\xxx\abc.jpg c:\zzz
    copy e:\yyy\test.py c:\zzz
    
    # 复制d盘下xxx目录的py文件文件到e盘yyy目录
    copy d:\xxx\*.py e:\yyy
    
  • xcopy在copy基础上支持复制目录(目录下所有文件和文件夹)

  • /s代表subdirectories,复制子目录及文件,但不包括空目录

  • /e代表empty,复制子目录及文件,同时包括空目录

  • 不加/s或者/e不会递归复制,只会复制当前目录下的文件

  • /i代表if,如果目的目录不存在,会自动创建

  • /y代表yes to all,不需要确认直接覆盖同名文件

  • /q代表quiet,不显示复制的详细信息,只显示错误信息

  • /h代表hide,隐藏文件和系统文件也会复制

  • /d代表date,同名文件,目的地文件比源文件的时间要新,则不复制

  • 实践得知,如果文件时间相同也不会复制,只有原路径比目的路径新才会复制

  • 而且这种情况大多会处于同名情况,覆盖会提示,可以配合/y使用

  • 如果/d配合/s参数,一般都是针对目录本身的时间,目录内的文件时间会被忽略

    # 复制e盘xxx\abc目录到上一级文件夹,不包含空目录
    xcopy /s e:\xxx\abc ..
    
    # 复制e盘xxx\abc目录到当前文件夹,包含空目录
    xcopy /e e:\xxx\abc .
    
    # 复制e盘xxx\abc目录到d盘qqq目录,目的地目录不存在
    xcopy /si e:\xxx\abc d:\qqq
    
    # 复制e盘xxx\abc文件(不递归)到d盘qqq目录,不需确认直接覆盖
    xcopy /y e:\xxx\abc d:\qqq
    
    # 复制e盘xxx\abc文件(不递归)到d盘qqq目录,只显示错误信息
    xcopy /q e:\xxx\abc d:\qqq
    
    # 复制e盘xxx\abc文件(不递归)到d盘qqq目录,原路径带有隐藏文件
    xcopy /h e:\xxx\abc d:\qqq
    
    # 复制e盘xxx\abc文件(不递归)到d盘qqq目录,原路径旧的时间不复制
    xcopy /d e:\xxx\abc d:\qqq
    
    # 多个参数结合使用
    # 复制目录,旧的时间不复制,同名覆盖不确认,复制隐藏文件
    xcopy /sdyh e:\xxx\abc d:\qqq
    
    

move(移动目录有问题)

  • 用于移动文件或目录,也可重命名文件和目录

  • 重命名的功能和rename是一样的,rename可直接忽略不用

  • 只有一个y(yes to all)选项,自动覆盖不需确认

  • 移动目录时出现拒绝访问,无论是授予所有权限或更改只读属性,管理员运行cmd都不行

  • 所以下面不会举例移动目录,并且也多留意写脚本时可能其他电脑也会不支持move

    # 移动txt文件
    move e:\xxx\*.txt d:\yyy
    
    # 移动文件,覆盖不确认
    move /y e:\xxx\*.txt d:\yyy
    
    # 移动目录,且覆盖不确认
    # 暂无例子,因为公司电脑move一直拒绝访问
    
    # 重命名文件
    move abc.txt ttt.txt
    
    # 重命名目录
    move def qwer
    
    # 移动文件并重命名
    move e:\xxx\abc.txt d:\yyy\ttt.txt
    

del

  • 删除文件(谨慎使用,删除的文件不在回收站,而是永久删除),常用的参数有/f /q /s

  • /f代表force强制删除只读文件,

  • /q代表quiet,删除文件夹时不需要确认(删除一个或多个文件不需要确认)

  • /s代表subdirectories,删除子目录下指定的文件

  • 基本格式:del 参数 文件名

  • 文件名可以是一个文件、多个文件(空格隔开)、目录列表

  • 如果是删除目录,只会删除目录下的文件,该目录还是会存在,需要用rmdir删除目录

    # 删除e:\xxx目录下的test.txt文件
    del e:\xxx\test.txt
    
    # 删除当前目录下的test.txt和test.bat文件
    del test.txt test.bat
    
    # 删除e:\xxx目录下的所有文件,无需确认
    del /q e:\xxx
    
    # 删除e:\xxx目录下的py文件,不包含子目录下的文件
    del e:\xxx\*.py
    
    # 删除e盘xxx目录(目录内所有文件)和e盘下所有py文件(当前cmd就在e盘)
    # 主要是和上面做对比,空格隔开说明是两个不同文件(或目录)
    del xxx *.py
    
    # 删除e:\xxx目录下的py文件,包含子目录下的文件
    del /s /q e:\xxx\*.py
    

type

  • 显示文本内容

  • 另一个功能,创建空文本

    # 显示abc.txt文本内容
    type abc.txt
    
    # 创建空文件到指定路径
    type nul > e:\xxx\null.txt
    

rename

  • rename功能可以由move命令完全替代,这里不写相关内容,感兴趣可以cmd rename /?查看

findstr

  • 搜索文本内容,dir是搜索目录下的文件,两者有区别

  • 上个命令的输出结果作为输入传递给findstr进行搜索(类似于linux的grep)

  • 不加参数代表符合条件的该行会被输出

  • 基本格式:

    • findstr 参数 字符串 [文件路径]

      # 查找当前txt文件包含abc字符串的行
      findstr abc test.txt
      
    • cmd | findstr 参数 字符串

      # 查找当前txt文件包含abc字符串的行
      type test.txt | findstr abc
      
  • 有以下一些常用参数:

    多个参数可以合并,比如/i /v,可以合并成/iv

    # 文本test.txt内容
    111222333444555666abc
    abcdefg12jk
    hiJKlmn12defAB
    1a2b3c4d5f34mn
    0QQ1df2gh3MMaBC
    

    搜索文本相关

    # 无参(就是默认/l),搜索匹配行,搜索带有txt的行
    findstr abc test.txt
    
    # /i(ignore),忽略大小写,搜索带有a或A的行
    findstr /i abc test.txt
    
    # /b(begin),只匹配开头,搜索1开头的行
    findstr /b 1 test.txt
    
    # /e(end),只匹配结尾,搜索c结尾的行
    findstr /e c test.txt
    
    # /r(regex),支持正则,搜索包含6789mA字符的行
    # 只支持简单正则,字母和数字,限定符(匹配次数)和预定义字符(\d \w)无法识别
    findstr /r [6-9mA] test.txt
    
    # /v(invert/reverse),反向搜索,输出不包含abc的行
    findstr /v abc test.txt
    
    # /n(number),显示匹配行的行数
    findstr /n abc test.txt
    
    # /c,把字符串当文本去搜索内容,可以把通配符和正则的字符也当成普通文本匹配
    # 正常情况下搜索字母数字加不加/c参数不影响结果,但是有特殊符号最好要加/c
    findstr /c:abcd test.txt
    

    搜索目录相关

    虽是搜索目录,但是还是搜目录下文件的内容

    如果不加路径,默认是cmd当前路径,但最好指定路径

    路径最好范围越窄越好,太宽(搜c或d盘)会导致太多文件符合条件

    *代表所有文件,但不建议搜所有文件,有时会把图片或其他格式文件一起搜出来

    会显示乱码且图片视频等类型本身就不是要搜索的范围,因此搜索最好指定文件后缀

    搜索目录时会有一个坑点,需要特别注意,如果文件里面有中文时

    很可能会出现乱码,乱码可能会导致搜索终止且出现FINDSTR: 写入错误

    如果文本确认是utf8格式的话,可以在搜索前先chcp 65001改一下编码格式

    # /s(search),搜索指定目录及其子目录下的所有文件,显示匹配的文件名+行内容
    
    # 匹配当前路径下有abc字符串的所有文件
    findstr /s abc *
    # 匹配d盘xxx目录下有abc字符串的txt文件
    findstr /s abc d:\xxx *.txt
    
    
    # /m(match),只显示匹配的文件名,不显示内容
    # 一般都配套/s使用,很少单独使用
    
    # 匹配e盘xxx目录下有exception字符串的py文件且忽略大小写,且只显示文件名
    findstr /ism exception e:\xxx *.py
    
    
    # /d(directory),查找以分号为分隔符的目录列表
    # 其实就是/s参数的一个扩展,/s只能指定一个路径,/d指定多个路径
    
    # 匹配多个路径有@echo字符串开头的文件名,忽略大小写,后缀为.bat,只显示文件名
    # 如果多个参数合并,某个参数要加选项,该参数要写在最后,如下例子/d有额外选项
    # 如果是多个参数要加选项,那么这些参数需要隔开,不能合并写
    findstr /bimd:d:\xxx;e:\xxx\yyy @echo *.bat
    

其他常用命令

date

  • 显示日期,要加/t参数,/t参数没有单词缩写意思

  • 不加/t参数是修改日期,修改需要管理员权限

    # 显示日期
    date /t
    echo %date%
    
    # 修改日期
    date yyyy/mm/dd
    

time

  • 显示时间,用法和date一样

    # 显示时间
    time /t
    echo %time%
    
    # 修改时间
    time xx:xx
    

cls

  • 清除屏蔽内容,无任何参数

    cls
    

tasklist

  • 显示本地计算机上所有进程的信息

  • 也可以显示远程计算机,但是很少用,一般查看本地计算机多,远程的参数使用/?查看

  • 本地计算机查看进程常用参数:/fi

  • /fi代表filter,可以指定过滤器,按照给定的规则可以对进程进一步过滤

  • 常用的有status(进程状态,运行或暂停两种),pid(process id),memusage(内存使用)

  • imagename也作为过滤使用,但是不支持模糊匹配,只能全匹配

  • 相对来说配合findstr搜索效果会更好

  • 运算符分别有:

  • eq(equal),ne(not equal),gt(great than),lt(less than),ge(great equal),le(less equal)

    # 查看运行中的进程
    tasklist /fi "status eq running"
    
    # 根据pid查找进程
    tasklist /fi "pid eq 108368"
    
    # 查看微信进程(有两种方式,推荐findstr方式)
    tasklist |findstr /i wechat
    tasklist /fi "imagename eq wechat.exe"
    
    # 查看内存大于100m的进程,默认单位是kb
    tasklist /fi "memusage ge 102400"
    

taskkill

  • 根据进程id或进程名字终止进程

  • 参数和tasklist差不多,也有远程参数,这里用的不多,用到时使用/?获取

  • 常用的有pid(process id),im(imagename),t(terminatechildren),fi(filter),f(force强制终止)

  • pid只能写一个id,终止一般需要加上/t参数,终止其子进程

  • 一般都需要加/f参数才能终止进程

  • im参数不能直接使用通配符,需要使用/fi参数才支持通配符

  • 但可能会误删除别的进程,所以通配符删除时要谨慎确认是不是自己要删除的

    # 根据pid强行终止网易云音乐进程及其子进程,需要先通过tasklist获取pid
    taskkill /f /t /pid xxxxx
    
    # 根据镜像名称强行终止网易云音乐进程
    taskkill /f /im cloudmusic.exe
    
    # 强制终止wechat相关的进程,慎重使用,最起码要tasklist确认是否包含除微信外的进程
    # 只能是*放最后才能识别,类似的(*wechat*,wechat*.exe全部无法识别)
    taskkill /f /fi "imagename eq wechat*"
    

ipconfig

  • 有很多参数但是不怎么用,只需要知道这个命令可以获取本机ip即可

  • 因为命令简单,这里不介绍,但运用上面所学知识写了个获取ip的脚本

  • 但需要把脚本编码格式改为gbk,否则脚本写的中文和获取ipconfig的中文乱码,无法过滤

  • 或者通过chcp 65001可以把以太网改为英文ethernet,可以正常过滤

  • 后续可以把该脚本作为子脚本被调用,可以在父脚本中获取到ip

    @echo off
    chcp 65001>nul
    setlocal EnableDelayedExpansion
    ::获取以太网ip所在行,未处理数据
    set flag=0
    for /f "delims=" %%i in ('ipconfig') do (
    	echo %%i|findstr /i "ethernet">nul && set flag=1
    	if !flag!==1 (
    		echo %%i|findstr /i ipv4>nul && set ip_str=%%i && goto end
    	)
    )
    :end
    
    ::处理数据
    for /f "delims=: tokens=2" %%i in ("%ip_str%") do (set ip=%%i)
    ::去除空格
    echo %ip: =%
    pause
    

ping

  • 检测两台主机之间网络情况

  • 格式:ping 参数 域名

  • ping的时候会显示ip地址(数字),所以可通过ping的方式从域名拿到ip做进一步的操作

  • ctrl+c可以停止请求并退出ping

  • /t代表持续发送,手动ctrl+c才会停止

  • /n指定发送数据包数量,默认是发4次就结束

    # 默认格式
    ping www.baidu.com
    
    # 一直发送
    ping /t www.baidu.com
    
    # 发送10次
    ping /n 10 www.baidu.com
    

telnet

  • 可能会出现telnet不是内部或外部命令,说明电脑没有安装telnet

  • cmd输入control,选择程序和功能,选择启动或关闭windows功能,勾选telnet客户端即可

  • telnet是用来远程登录,但存在安全性问题,而使用ssh会更安全

  • ssh具有加密的远程登录和命令执行功能

  • 相对来说telnet只适用于验证远程主机地址和端口是否能连接

  • 如果能跳转说明该地址和端口能访问,不能跳转说明不能访问

    telnet www.baidu.com 80
    

exit

  • 退出cmd窗口或批处理脚本

  • 在批处理脚本中用的不多,更多的是用pause暂停

  • 因为很多时候要看返回信息

  • 一般都是在cmd输一些内容后不用了直接exit退出,比点x要优雅而已

    exit
    

tree

  • 以图形方式显示目录结构(仅目录,文件不显示)

  • 注意不要在范围太广使用,数据特别多,看起来也费劲,尽量缩小要查询的范围

  • /f代表files,显示文件

    # 查看e:\xxx目录结构
    tree e:\xxx
    
    # 查看e:\xxx目录结构,同时显示文件
    tree /f e:\xxx
    

shutdown

  • 关闭计算机

  • 可以远程关闭操作,但不常用,等以后用到可以再详细了解然后补充

  • 不加参数不会立即关闭,要加/s参数才会关闭

  • /s代表shutdown立即关闭

  • /r代表reboot立即重启

  • /t代表time延迟关机,以秒做单位(需要配合/s或/r参数,单独使用无效果)

  • /a代表abort取消计划的关机/重启任务

  • /c代表comment关机时提示自定义写的消息

    # 立即关闭计算机
    shutdown /s 
    # 立即重启计算机
    shutdown /r
    # 延迟10分钟后关闭计算机
    shutdown /s /t 600
    # 取消关闭计算机计划
    shutdown /a
    # 延迟10分钟关闭计算机并且提示电脑10分钟后即将关闭
    shutdown /s /t 600 /c "this computer will be closed in ten minutes"
    

more

  • 分页显示屏幕内容,与linux的less相似

  • 空格往下翻一页,回车往下翻一行,不支持往上翻

  • 按q代表quit退出more界面

  • 按=代表显示当前行号

  • 有两种使用方式:

  • more 文件名

  • 命令 | more

    # more打开文件分页
    more e:\xxx\test.txt
    
    # 命令的输出分页显示
    tree e:\xxx | more
    

特殊符号

重定向符号

<
  • 输入重定向,将文件内容作为命令的标准输入(stdin)
# txt文件内容重定向给findstr命令,带有hello字符串的那行会被输出
findstr /i hello < e:\test.txt

# 还可以输入重定向和输出重定向一起使用,过滤出来的内容再保存到文件中
findstr /i hello < e:\test.txt > e:\test1.txt
>
  • 输出重定向,原本输出到控制台的内容输出到文本中
  • 如果文件已存在,文件内容将会被覆盖,文件不存在会自动新建并写入内容
  • 有时会有这种需求,执行某个命令会返回结果,如果不想要这个结果,可以重定向到nul
echo hello world > e:\test.txt

# 输出的内容丢弃,不显示在控制台
chcp 65001 > nul
>>
  • 追加操作的输出重定向,与上面不同的是不会覆盖只会追加
  • 文件不存在也会自动新建并写入内容
echo hello cmd hello world >> e:\test.txt
|
  • 两个命令的连接,让第一个命令的输出变为第二个命令的输入
  • 管道符一般配合findstr使用,对第一个命令的内容进行过滤
# 查找cmd当前路径下含有txt的名字
# /i代表忽略大小写
dir | findstr /i txt

其他命令

&和&&
  • &连接两个或多个命令,前一个命令是否执行成功都会执行下一个命令
  • &&连接两个或多个命令,前一个命令执行成功(errorlevel为0),才会执行下一个命令
  • 如果前一个命令执行不成功,则会被跳过不执行
# 第一个命令执行不成功,使用&连接
echo aaa |findstr ab & echo aaa

# 第一个命令执行不成功,使用&&连接
echo aaa |findstr ab && echo aaa
||
  • ||连接两个命令,与&&相反,前一个命令执行不成功时,才会执行下一个命令
  • 如果前一个命令执行成功,则会被跳过不执行
  • 可以使用&&和||实现类似python的三元运算符
# 第一个命令执行不成功,使用||连接
echo aaa |findstr ab || echo aaa

# 三元运算符例子
# 输出一个字符串,如果包含abc,输出contain,如果不包含则输出not contain
echo abcdefg | findstr abc > nul && echo contain || echo not contain
echo abcdefg | findstr abcc > nul && echo contain || echo not contain
^
  • 转义符,有两个作用:
  • 第一个取消含有特殊意义的字符当作普通字符处理
  • 第二个是转义换行符,通常在if结构中遇到
  • 当if一行写不完需要换行写,行尾加上^代表连接两行的代码,不加cmd识别不出会报错
# 转义字符
# 如果不加^转义|,会把它当成管道符,提示命令语法不正确
echo aaa^|

# 转义换行符
set c=-5
if %c% lss -10 (echo c^<-10)^
else if %c% lss 0 (echo c^<0)^
else (echo c^>0)
!
  • 延迟环境变量扩展符
  • 当开启延迟环境变量时,引用变量不再使用%var%,而是使用!var!
  • 该符号只有一种用途,并且上面setlocal章节有解释,这里就不再举例,可看上面例子

锦上添花命令

  • title

    该命令可以自定义cmd窗口的标题,不定义默认显示cmd.exe的路径

    title custom my title
    
  • color

    该命令可以设置背景颜色和文本颜色,不设置的话默认黑色背景,白色文本

    使用0-F十六进制来控制颜色,第一个数字指定背景色,第二个数字指定文本色

    实际操作过,颜色种类少,没有自己想要的颜色,还不如默认黑白色,加了颜色更难看

    # 背景淡绿色,文本黑色
    color B0
    

疑难杂症或坑点

cmd窗口中文显示乱码

编码格式不一样导致的乱码,cmd默认是GBK或GB2312编码,编辑的文本可能是utf-8

有三种解决方式:

  1. bat脚本使用notepad++打开,把编码格式改为GB2312,重新执行脚本即可

  2. bat脚本增加一行命令,可以把控制台切换到utf-8编码格式

    chcp 65001 > nul
    
  3. bat脚本增加一行命令,把控制台切换到gbk格式

    chcp 936 > nul
    

上面三种方式,第一种需要人为改动,不够好,第二第三种可以脚本自适应编码格式,推荐

空格和特殊符号处理

无论是cmd输入命令或写bat脚本,命令很多时候都是以空格作为分隔符,所以某些文件名字或者变量本身包含空格或者特殊符号等,最好都使用双引号括起来,避免出现问题,如果一出现问题,脚本执行就会直接闪退,但又很难排查原因,很费时间。尽量先把这些简单问题规避好。

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值