bat批处理脚本
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一起使用
-
但是自己研究时发现,标签大致分为两个作用:
- 用于流程控制,但这个可以使用if代替
- 用于循环,但这个也可以使用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循环一些注意小事项或实用小技巧
-
实际中for循环使用/f参数频率最高,特别是忽略空格,都要加上delims
-
delims和tokens=*实现的效果是一样的
-
do后面命令有多行,需要换行写,挤在一行会出问题
-
set集合里面是命令,需要使用单引号括起来,双引号不行
-
for命令中不能实现传入一个字符串,把每个字符遍历出来,这个需要goto实现
-
调用子脚本并且获取其输出的值,可作为父脚本变量使用,可以使用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
有三种解决方式:
-
bat脚本使用notepad++打开,把编码格式改为GB2312,重新执行脚本即可
-
bat脚本增加一行命令,可以把控制台切换到utf-8编码格式
chcp 65001 > nul
-
bat脚本增加一行命令,把控制台切换到gbk格式
chcp 936 > nul
上面三种方式,第一种需要人为改动,不够好,第二第三种可以脚本自适应编码格式,推荐
空格和特殊符号处理
无论是cmd输入命令或写bat脚本,命令很多时候都是以空格作为分隔符,所以某些文件名字或者变量本身包含空格或者特殊符号等,最好都使用双引号括起来,避免出现问题,如果一出现问题,脚本执行就会直接闪退,但又很难排查原因,很费时间。尽量先把这些简单问题规避好。