bat详解

bat详解无论是 cmd 输入命令或写 bat 脚本 命令很多时候都是以空格作为分隔符 所以某些文件名字或者变量本身包含空格或者特殊符号等 最好都使用双引号括起来 避免出现问题 如果一出现问题 脚本执行就会直接闪退

大家好,欢迎来到IT知识分享网。

bat批处理脚本

cmd命令官方文档

https://blog.csdn.net/_/article/details/

https://blog.csdn.net/spw/article/details/

https://blog.csdn.net/_/article/details/


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

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

    # test.txt内容 test qwwee  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-qwwee- 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盘q目录,目的地目录不存在 xcopy /si e:\xxx\abc d:\q # 复制e盘xxx\abc文件(不递归)到d盘q目录,不需确认直接覆盖 xcopy /y e:\xxx\abc d:\q # 复制e盘xxx\abc文件(不递归)到d盘q目录,只显示错误信息 xcopy /q e:\xxx\abc d:\q # 复制e盘xxx\abc文件(不递归)到d盘q目录,原路径带有隐藏文件 xcopy /h e:\xxx\abc d:\q # 复制e盘xxx\abc文件(不递归)到d盘q目录,原路径旧的时间不复制 xcopy /d e:\xxx\abc d:\q # 多个参数结合使用 # 复制目录,旧的时间不复制,同名覆盖不确认,复制隐藏文件 xcopy /sdyh e:\xxx\abc d:\q 

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内容 abc abcdefg12jk hiJKlmn12defAB 1a2b3c4d5f34mn 01df2gh3MMaBC 

    搜索文本相关

    # 无参(就是默认/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 " # 查看微信进程(有两种方式,推荐findstr方式) tasklist |findstr /i wechat tasklist /fi "imagename eq wechat.exe" # 查看内存大于100m的进程,默认单位是kb tasklist /fi "memusage ge " 

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

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/135199.html

(0)
上一篇 2025-07-06 15:26
下一篇 2025-07-06 15:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信