其他分享
首页 > 其他分享> > cmd命令及bat批处理入门

cmd命令及bat批处理入门

作者:互联网

本文主要来自批处理之家的 《批处理标准教程.pdf》

基础语法

注释

注释有二种类型:

两者略有区别:当打开回显时,rem 注释会回显出来,:: 则不会显示。

@关闭回显

在运行一条命令时,这条命令本身也会显示在控制台上,譬如编写如下内容的一个 .bat 文件,双击运行

echo 'bbb'

pause

输出如下:

C:\Users\wztshine\Desktop\bat>echo 'bbb'   # 这条命令自身也显示出来了
'bbb'

C:\Users\wztshine\Desktop\bat>pause        # 这条命令也显示出来了
请按任意键继续. . .

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

:: @ 用来关闭 echo off 自身的回显
@echo off
echo 'bbb'
pause

输出:

'bbb'
请按任意键继续. . .

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

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

批处理文件

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

C:\Users\wztshine\Desktop\bat>test.bat   # 在命令行窗口中,作为可执行程序来执行
'bbb'
请按任意键继续. . .

符号

&, && 可以用来连接多个命令:

C:\Users\wztshine\Videos>set a=5 & set b=10

C:\Users\wztshine\Videos>echo %a% %b%
5  10

-/ 是等价的,用来指定选项:

timeout /t 5

转义符号

对于一些特殊符号 ^ > >> & && | || ,需要使用转义符 ^ 进行转义:

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 ,也就是两者之一,不能同时使用。

参数和变量

命令行参数

批处理文件可以接受命令行参数,通过变量%1%2%3等来获取。

@echo off

echo %1 %2
pause

执行:

C:\Users\wztshine\Desktop\bat>test.bat a b c  # 传递了三个参数:a, b, c; 多余的参数会忽略
a b
请按任意键继续. . .

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
2
C:\Users\wztshine\Desktop\bat>set /A var=-10
-10
C:\Users\wztshine\Desktop\bat>set var=bac    # 设置字符串

C:\Users\wztshine\Desktop\bat>echo %var%     # 显示变量的值
bac

%变量名% 是获取变量值的语法。

全局变量和局部变量

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

@echo off

set a=10

:: 这是一个局部变量
setlocal
set b=20    
endlocal

echo %a%
:: 此时变量 b 会是未声明的状态,因此不会打印出任何东西
echo %b%


pause

双击运行上述文件:

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

环境变量

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

C:\Users\wztshine\Desktop\bat>echo %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 defined var echo "var is not empty"

pause

字符串判断

字符串判断,最好使用双引号将字符串包裹起来,这样可以防止字符串包含空格

@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!

字符串长度

@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

字符串转数字

:: var 是个字符串
set var=23

:: c 也是字符串
set c=%var%+5
echo %c%

:: /A 选项,就变成了数字 28
set /A c=%var%+5

截取字符串

语法:

%变量:~start,end%

上面的 start,end 都是索引,从0开始。可以是正数和负数

实例: 注意负号

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开始,截取到倒数第一个字符

输出:

ello
orld
llo world
ello worl

替换/删除字符串

@echo off

set x=hello world

:: 将 hello 替换成 beautiful
echo %x:hello=beautiful%

:: 将 hello 替换成空(删掉)
echo %x:hello=%

pause

注意是全部替换,而不是只替换一次

输出:

beautiful world
 world
请按任意键继续. . .

使用通配符:

C:\Users\wztshine>set a=123456789

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

C:\Users\wztshine>echo %a:*4=0%   # 通配符写在左侧才生效
056789

字符串大小写替换

@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

数组

建立数组

通过 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 用来打印信息

:: 显示回显状态
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

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%
3


C:\>set x=1
C:\>set y=2
C:\>set /a n=x+y
3

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

表达式符号

( )

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

+ - * / %

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

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

位运算符

<<, >>, &, ^, |

用户输入

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

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

不换行输出

@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 (commands)

注意

语法:

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
yes

判断文件或文件夹存在

if [not] exist "path"

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

实例:

@echo off
if exist "C:\Program Files\" (
	echo 文件夹存在
) else (
	echo 文件夹不存在
)
pause

实例2:

@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

判断字符串

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

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 处理文件

基础语法:

for %%variable in (set) do command
  • %%variable:是自定义的变量,如:%%i;在批处理文件中使用两个百分号 %%i ,在cmd命令行使用一个百分号%i

  • set: 是一个集合,可以是多个文件

  • command: 是要执行的命令,多行命令可以放在圆括号里面

譬如:

@echo off

:: 这里我们处理两个文件:a.txt 和 "b c.txt"
for %%i in (a.txt "b c.txt") do (
  echo 正在处理:%%i
)
pause

通配符

* 匹配任意多个字符。? 匹配 0 或 1 个字符。

@echo off

:: * 用来匹配零个或一个或多个任意字符; ? 表示零个或一个任意字符
for %%i in (*.txt ??.log) do (
  echo 正在处理:%%i
)
pause

变量扩展

遍历文件时的变量,还支持变量扩展:关于变量扩展,见后文的《变量扩展》章节

@echo off

for %%i in ("C:\Program Files\7-Zip\7z.exe") do (
    echo 文件:%%i
    echo 删除引号:%%~i
    echo 文件所在的驱动器:%%~di
    echo 文件所在的路径:%%~pi
    echo 文件名:%%~ni
    echo 文件扩展名:%%~xi
    echo 文件路径的短名:%%~si
    echo 文件的日期/时间:%%~ti
    echo 文件的大小:%%~zi
)
pause

批量重命名的例子:

@echo off

:: 查找当前路径下所有的 txt 文件,并重命名加前缀:new_
for %%i in (*.txt) do (
    echo 正在处理:%%i
    ren "%%i" "new_%%i"
)
pause

for /d 遍历文件夹

/d 选项用来处理文件夹。/d 无法搜索到隐藏的文件夹

@echo off

:: 想要遍历当前文件夹,可以写成 * 或者 ./* ,不需要加引号
for /d %%i in ("C:\Test\*") do (
    echo %%i
)
pause

递归遍历文件夹

/r 选项可以递归遍历文件夹,语法:for /r path /d in (path) do command

@echo off

:: ./ 代表了当前路径, ./* 代表了路径下的任意文件夹
for /r ./ /d %%i in (./*) do (
    echo %%i
)
pause

for /r 枚举目录树处理文件

/r path 可以递归遍历 path 下的文件夹,因此我们可以递归查找所有文件夹下的文件:

如果/r 后面不写路径,则默认是当前目录。

@echo off

for /r "C:\Test\" %%i in (*.txt) do (
    echo %%i
)
pause

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:

1 2
3 4

我们读取它:

@echo off
REM 默认 空格和制表符 作为分隔符
for /f %%i in (a.txt) do (
    echo,%%i
)
pause

输出:

1
3
请按任意键继续. . .

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

我们手动设置分隔符:

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

输出:

1 2
3 4

过滤空白行:

@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

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

语法:

tokens=x,y,m-n

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

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

删除行前空白:

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

eol

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
skip

用来跳过几行。

@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

处理命令输出

@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

语法: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 的意思,相当于文件末尾。

退出程序

三种方式退出程序:

区别:

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

exit 彻底退出脚本。

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

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

start

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

语法:

START ["title"] [/Dpath] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED] [/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENORMAL | /BELOWNORMAL] [/WAIT] [/B] [command/program] [parameters]

参数:[] 代表可选选项

start 可以打开程序,路径,文件,网址等,譬如:

@echo off
start D:\Tencent\QQ\Bin\QQ.exe
start C:\批处理教程.txt

::打开 E 盘
start E:
start www.baidu.com
exit

带有空格的文件夹:

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

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

call

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

语法:

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

参数说明:

创建代码段

我们可以使用 :name 的方式,来创建一个名为 name 的代码段,一个代码段仅仅是用来标记一段代码,它并不是一个函数,它不需要调用就能执行:

@echo off

:: 这个代码段,没有设置结尾
:func
    echo hello

echo world

pause

输出:

hello
world
请按任意键继续. . .

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

:func
    echo hello
    pause
    goto :eof
    
echo world
pause

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

调用其他批处理文件

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

调用本文件的代码段

@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

:sub
:: 我们将第二个变量赋值给第一个变量:return=Hello
set %1=%2

输出:

returned: Hello

另一个求和的例子:

@echo off
set sum=0
call :sub sum 10 20 35
echo 数据求和结果: %sum%
pause>nul
goto :eof

:sub
set /a %1=%1+%2
:: shift /2 的作用是:从第二参数开始,向左移动一位:将 %3 移位到 %2,将 %4 移位到 %3,等等;并且不影响 %0 和 %1。
shift /2
if not "%2"=="" goto sub

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


:sub
set /a %1=%1+%2
:: 从第二个参数开始,向左移动
shift /2
:: 判断参数是否为空,否则继续
if not "%2"=="" goto sub

分析一下:

  • 调用 :sub 这个代码段时,传递了参数:"sum 1 2 3 4 5 6 7 8 9"
  • 刚进入 sub 代码段时:set /a %1=%1+%2 会变成:set /a sum=sum+1, 等号右边的 sum 是变量 %sum%,因为等号右边的变量可以省略 %, 所以最终是 set /a sum=0+1

title

设置窗口名称:

title BAT

color

设置背景色和前景文字颜色

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

支持的颜色如下:

譬如:

color F5

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

mode

它有两个主要作用:

设置窗口大小

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

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

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

语法:

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

del 没有带参数的情况下,无法删除具有隐藏属性、只读属性或者系 统属性的文件。

::删除具有隐藏属性的文件 
del /a:h D:\test.txt

::删除具有只读属性的文件 
del /a:r D:\test.txt

::删除具有系统属性的文件 
del /a:s D:\test.txt

::所有文件都可以删除
del /a /f D:\test.txt

带对话的删除:

del /a /f /p D:\test.txt

不带对话,直接删除:

del /a /f /q D:\test.txt

支持通配符:

del D:\testssssss\*

遍历删除:

:: 会遍历当前路径下的所有子目录,来删除 test.txt 文件
del /a /f /p /s test.txt

RD / RMDIR

这两个命令完全一样,作用都是删除一个目录。 注意:rd 不支持通配符!rd 可以删除文件和文件夹

语法:

RD [/S] [/Q] [drive:]path

/S 除目录本身外,还将删除指定目录下的所有子目录和文件。用于删除目录树。

/Q 安静模式,删除目录时不要求确认

删除文件夹:

rd /s /q d:\test\t1

MOVE

移动文件,也可以重命名文件和目录。

移动文件到目录

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

/Y:如果目录有同名文件,不提示,直接覆盖

/-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

将一份或多份文件复制到另一个位置。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\

:: 通配符
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

在文件中搜索字符串。

语法:

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

参数说明:

支持通配符,可以在多个文件中查找:

@echo off
:: 显示不包含 abc 的行
find /v /i "abc" D:\*.txt

pause

例子:

现有 a.txt:

1
2
3

实例:

@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[ ...]] 

参数:

忽略大小写:

findstr /i abc a.txt

忽略大小写,在 a.txt 中查找包含 abc 的行

搜索 A 字符串 或 B 字符串

findstr /i "a c" a.txt

在 a.txt 中搜索 a 或者 c

注意:默认字符串中的空格,会作为分隔符分割字符串,然后将每一部分都作为单独的字段来查找,并且各字段是 的关系。

禁止空格分割:

上面说了,字符串中的空格会将字符串分割,然后用 的关系,来查找每个字符串。/c: 可以将带有空格字符串作为一个整体进行查找:

findstr /i /c:"a b c" a.txt

上面会将 a b c 作为一个整体进行查找过滤

搜索子目录:

@echo off
findstr /s /i Windows *.*
pause 

正则

findstr 支持正则表达式。

findstr "^[a-z]*$" 2.txt 

"<…>"表达式

这个表示精确查找一个字符串,\< 表示字符串的开头, \> 表示字符串结尾。

echo hello world computer|findstr "\<computer\>"

精确查找 computer 这个字符串。当然,上面的例子仅仅只是说明"<…>"的作用而已。上面程序其实 直接就 echo hello world computer|findstr "computer" 就可以了。

pushd, popd

就是用 pushd 标记路径,然后 popd 恢复路径。可以多次 pushd 和 popd 来保存和恢复路径。其实本质就是先进后出的栈。

C:\Users\wztshine>pushd c:\Users\wztshine   # 暂存当前路径

C:\Users\wztshine>cd \                      # 切换路径

C:\>popd                                    # 在其他路径 popd

C:\Users\wztshine>                          # 自动恢复之前存的路径

CMD

可以新建一个 cmd 命令窗口,并执行一些命令

语法:

CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF] [[/S] [/C | /K] string] 

参数:

实例:

cmd /k start c:

FC

比较两个文件或两个文件集并显示它们之间的不同

FC [/A] [/C] [/L] [/LBn] [/N] [/OFF[LINE]] [/T] [/U] [/W] [/nnnn] [drive1:][path1]filename1 [drive2:][path2]filename2 FC /B [drive1:][path1]filename1 [drive2:][path2]filename2

参数:

FORMAT

格式化磁盘

语法:

FORMAT volume [/FS:file-system] [/V:label] [/Q] [/A:size] [/C] [/X] 
FORMAT volume [/V:label] [/Q] [/F:size] 
FORMAT volume [/V:label] [/Q] [/T:tracks /N:sectors] 
FORMAT volume [/V:label] [/Q] 
FORMAT volume [/Q]

选项:

MORE

逐屏显示输出。

RECOVER

从损坏的磁盘中恢复可读取的信息。

RECOVER [drive:][path]filename

REPLACE

替换文件。

REPLACE [drive1:][path1]filename [drive2:][path2] [/A] [/P] [/R] [/W]

REPLACE [drive1:][path1]filename [drive2:][path2] [/P] [/R] [/S] [/W] [/U] 

[drive1:][path1]filename 指定源文件。

[drive2:][path2] 指定要替换文件的目录。

/A 把新文件加入目标目录。不能和 /S 或 /U 命令行开关搭配使用。

/P 替换文件或加入源文件之前会先提示您 进行确认

/R 替换只读文件以及未受保护的文件。

/S 替换目标目录中所有子目录的文件。不 能与 /A 命令选项搭配使用。

/W 等您插入磁盘以后再运行。

/U 只会替换或更新比源文件日期早的文 件。不能与 /A 命令行开关搭配使用。

shutdown

语法:

shutdown [-i | -l | -s | -r | -a] [-f] [-m \\computername] [-t xx] [-c "comment"] [-d up:xx:yy] 

800 秒后自动关机

shutdown /s /t 800

60秒后强制关机,并设置一个备注信息:April Fools

shutdown -s -f -t 60 -c "April Fools"

ver

显示系统版本

tree

以图形模式显示路径的目录结构。

语法:

TREE [drive:][path] [/F] [/A]
  • /F 显示每个文件夹中文件的名称(递归目录,包含子目录)。
  • /A 使用 ASCII 字符,而不使用扩展字符。
tree D:                # 显示 D 盘根目录结构
tree D:\tencent        # 显示 D 盘 tencent 目录结构
tree D:\tencent /f     # 显示 D 盘 tencent 目录结构及其所有文件
tree D:\tencent /a     # 以 ASCII 码显示 D 盘 tencent 目录结构
tree D:\tencent /f /a  # 以 ASCII 码显示 D 盘 tencent 目录结构及其所有文件

type

显示文本文件的内容。

type D:\test.txt

DIR

显示某个路径下的目录和文件。不指定路径,则默认显示当前路径下的所有文件和文件夹

语法:

DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N][/O[[:]sortorder]] [/P] [/Q] [/S] [/T[[:]timefield]] [/W] [/X] [/4] 

例子:

例 1: C:\>dir 显示 C 盘根目录文件列表

例 2:C:\>dir "program files" 显示 C:\program files 里面 的内容。注意:如果文件名包含空格,就必须用双引号,否则失败。 文件名不包含空格,则双引号可有可无。

例 3: C:\>dir /a 显示所有文件,包括系统文件和隐藏文件。/a 后面可以带参数,表示搜索具有指定属性的文件。 这里缺省情况下,就表示搜索所有文件。

例 4:C:\>dir /as 显示 C 盘里的系统文件及隐藏的文件及目录,其它不显示。

例 5: C:\>dir /ah 显示隐藏文件及文件夹。

例 6: C:\>dir /ad 只显示 C 盘的目录而不显示文件。

例 7: C:\>dir /a-d 只显示 C 盘的文件而不显示目录。以上都 是/a 后面带参数,表明搜索具备或者不具备(-d -r -h -a -s)指定属性的文件。

例 8: C:\>dir /o 显示 C 盘目录和文件顺序。

例 9: C:\>dir /o-g 目录在下面,文件在上面。

例 10:C:\>dir /on 按名称的字母顺序排列 C 盘的目录和文件。

例 11:C:\>dir /o-n 按名称的字母逆序排列 C 盘的目录和文件。

例 12:C:\>dir /oe 按扩展名的字母顺序排列 C 盘的目录和文件。

例13:C:\>dir /o-e 按扩展名的字母逆序排列C盘的目录和文件。

例 14:C:\>dir /od 按日期和时间顺序排列 C 盘的目录和文件(早的排前)

例 15:C:\>dir /o-d 按日期和时间逆序排列 C 盘的目录和文件(晚的排前)

例 16:C:\>dir /os 按文件的大小排列(大的排前)

例 17:C:\>dir /o-s 按文件的大小排列(小的排前)

例 18:C:\>dir /p /a /og windows 分页显示 C 盘 Windows 目录 和文件,也包括隐藏的目录和文件,并按照在文件之前分组显示。 windows 没有包含空格,那么有无双引号无所谓。

例 19:C:\>dir /p /w /a /og windows 分页并宽屏显示 C 盘 Windows 目录和文件,也包括隐藏的目录和文件,并按照在文件之前分组显示。

例20:C:\>dir /s /b regedit.exe 在C盘搜索regedit.exe路径。 如果要求显示详细信息,可以这么写 C:\>dir /s regedit.exe

例 22:F:\>dir /s /b *.mp3>E:\mp3.txt 搜索 F 盘每个角 落的 mp3 文件,生成列表后保存在 E 盘。

例 23:C:\>dir read???.txt 搜索 C 盘根目录下所有以 read 开头,后面最多跟三个字符的 txt 文件。

cd

CD 等于 CHDIR, 用来切换路径。

语法:

CD [/D] [drive:][path]
CD [..]
CD [\] 

/d 选项用来切换磁盘。譬如你从 C 盘 切换到 D 盘,必须使用这个选项。

.. 代表上层路径

\ 代表磁盘的根目录

例子:

C:\Users\wztshine>cd ..

C:\Users>cd \

C:\>cd /d D:

D:\>cd /d C:\Users

EXIT

退出 CMD.EXE 程序(命令翻译程序)或当前批处理脚本。

语法:

EXIT [/B] [exitCode] 

/B 选项用来仅退出脚本,而非 cmd.exe 进程。

exitCode 是退出码,可选范围是 0~255

譬如可以在脚本这样写,来设置退出脚本,并设置退出码:

exit /b 0

MD / MKDIR

MD 等于 MKDIR,用来创建目录(也就是创建文件夹),如果文件夹已经存在,会提示。

注意:路径使用 \, 而不是 /

md a\b\c  # 在当前路径下创建 a\b\c 三层文件夹

md D:\test

REN / RENAME

ren 等同于 rename,用来给文件夹或文件重命名

REN [drive:][path]name1 name2

注意:第一个参数是要重新命名的路径,第二个参数只能是名字,不能指定路径!

ren a.txt b.txt

ren D:\a.txt b.txt

内置变量

%errorlevel%

最近一次执行命令的退出码。成功是 0,错误是非 0 的数值。退出码的取值范围是 0~255

%ALLUSERSPROFILE%

返回“所有用户”配置文件的位置。

%APPDATA%

返回默认情况下应用程序存储数据的位置。

%CD%

返回当前目录字符串。也就是获得当前路径,并将其转换为字符串。

%CMDCMDLINE%

返回用来启动当前的 Cmd.exe 的准确命令行。

%CMDEXTVERSION%

返回当前的“命令处理程序扩展”的版本号。

%COMPUTERNAME%

返回计算机名称。

%COMSPEC%

返回命令行解释器可执行程序的准确路径。也就是返回 cmd.exe 的路径,一般在C:\WINDOWS\system32\cmd.exe。

%DATE%

返回当前日期字符串。和使用 date/t 效果一样。

%HOMEDRIVE%

返回连接到用户主目录的本地工作站驱动器号。基于主目录值而设置。用户主目录是在“本地用户和组”中指定的。

%HOMEPATH%

返回用户主目录的完整路径。基于主目录值而设置。用户主目录是在“本地用户和组”中指定的。

%HOMESHARE%

返回用户的共享目录的网络路径。基于主目录值而设置。用户主目录是在“本地用户和组”中指定的。

%LOGONSERVER%

返回验证当前登录会话的域控制器的名称。

%NUMBER_OF_PROCESSORS%

指定安装在计算机上的处理器数目(所有 CPU 的总核心数)。

%OS%

返回操作系统名称。

%PATH%

系统指定可执行文件的搜索路径。也就是在这些目录下的可执行文件

%PATHEXT%

返回操作系统认为可执行的文件扩展名的列表。

%PROCESSOR_ARCHITECTURE%

返回处理器的芯片体系结构。返回值为 x86 或 IA64或 RISC。这些都是常见的架构,或者称作指令集。

%PROCESSOR_IDENTFIER%

返回处理器说明。

%PROCESSOR_LEVEL%

返回计算机上安装的处理器型号。

%PROCESSOR_REVISION%

返回处理器版本号。

%PROMPT%

返回当前解释程序的命令提示符设置。由 Cmd.exe 生成。

%RANDOM%

返回 0 到 32767 之间的任意十进制数字。由 Cmd.exe 生成。

%SYSTEMDRIVE%

返回包含Windows server operation system根目录(即系统根目录)的驱动器。

%SYSTEMROOT%

返回 Windows server operation system 根目录位置。

%TEMP%和%TMP%

用户返回对当前登录用户可用的应用程序所使用的默认临时目录。有些应用程序需要 TEMP,而其他应用程序则需要 TMP。

%TIME%

返回当前时间字符串。使用与 time /t 命令相同的格式。

%USERDOMAIN%

返回包含用户账户的域的名称。

%USERNAME%

返回当前登录的用户的名称。

%USERPROFILE%

返回当前用户的配置文件的位置,即当前用户的家目录

%WINDIR%

返回操作系统目录的位置。

我的电脑上执行结果:

echo %errorlevel% 0
echo %ALLUSERSPROFILE% C:\ProgramData
echo %APPDATA% C:\Users\wztshine\AppData\Roaming
echo %CD% C:\Users\wztshine\Desktop\bat_test
echo %CMDCMDLINE% C:\Windows\system32\cmd.exe /c ""C:\Users\wztshine\Desktop\bat\test.bat" "
echo %CMDEXTVERSION% 2
echo %COMPUTERNAME% DESKTOP-DCBC2US
echo %COMSPEC% C:\Windows\system32\cmd.exe
echo %DATE% 2022/05/20 周五
echo %HOMEDRIVE% C:
echo %HOMEPATH% \Users\wztshine
echo %HOMESHARE% ECHO 处于关闭状态。
echo %LOGONSERVER% [\DESKTOP-DCBVSO](file://DESKTOP-DCBVSO)
echo %NUMBER_OF_PROCESSORS% 4
echo %OS% Windows_NT
echo %PATH% D:\AZ\py3.10.1\Scripts;D:\AZ\py3.10.1; .....
echo %PATHEXT% .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW
echo %PROCESSOR_ARCHITECTURE% AMD64
echo %PROCESSOR_IDENTFIER% ECHO 处于关闭状态。
echo %PROCESSOR_LEVEL% 6
echo %PROCESSOR_REVISION% 3c06
echo %PROMPT% $P$G
echo %RANDOM% 19717
echo %SYSTEMDRIVE% C:
echo %SYSTEMROOT% C:\Windows
echo %TEMP% %TMP% C:\Users\wztshine\AppData\Local\Temp C:\Users\wztshine\AppData\Local\Temp
echo %TIME% 14:05.9
echo %USERDOMAIN% DESKTOP-DCBC2CN
echo %USERNAME% wztshine
echo %USERPROFILE% C:\Users\wztshine
echo %WINDIR% C:\Windows

变量延迟扩展

setlocal enabledelayedexpansion 可以设置变量延迟。

先看一个很简单的例子,猜测一下输出结果是啥:

@echo off

set a=Hello
if "%a%" == "Hello" (
    set a=World
    echo %a%
)
echo %a%
pause

输出:

Hello
World

为什么输出了 Hello 呢?按道理说,应该输出两次 World 才对。

这是因为 if 后面的圆括号以及圆括号里面的所有命令,都会被当作一条完整的语句来进行预处理,所谓预处理,就是先将语句中所有的变量 %var%,都用变量的值替换掉。

因此程序执行到 if 语句时,找到语句中的变量 %a% ,并用它的值 Hello 来替换,因此 if 语句中的 echo %a% 就变成了 echo Hello,当 if 语句执行完毕后,set a=World 也就生效了,因此最后一个 echo %a% 输出的是 World

所谓变量延迟,就是禁用预处理,让变量实时的更新。但是需要注意的是,要实时更新的变量,不能再用 %var% 这种格式,而是要用 !var! 这种格式

启用变量延迟:

@echo off

set a=Hello

:: 启用变量延迟扩展
setlocal enabledelayedexpansion
if "%a%" == "Hello" (
    set a=World
    :: 注意这里要用 !a! 这种形式
    echo !a!
)

echo %a%
pause

输出:

World
World

注意:

以后所有的复合语句(“for if else”等含有语句块的语句和用“& | && ||”等连接起来的复合语句),如果要实时更新某个变量,都要使用变量延迟!否则预期结果可能和你猜想的不同。

首先要明白什么是“复合语句”,所谓“复合语句”就是指一对 () 里的所有命令。比如 fordo 后面,如:

for /f "delims=" %%i in (a.txt) do (
    set var=%%i
    echo %%i
    set num=%%i
) 

当然,不仅仅是 for 命令的括号里面是复合语句,实际上,所有用圆括号包裹的命令,都是复合语句。通过管道命令 &、 &&、|、|| 连接起来的命令也是复合语句。

如果在复合语句之外引用变量,则使用 %var% !var!都是可以的。若想在复合语句中使用实时的变量,则必须使用 !var!。如果在复合语句中还是使用 %var% 变量,那么得到的变量将是复合语句之前 var 的值,此时如果 var 在复合语句之前没有定义,那么值为空值

变量扩展

我们不仅可以使用 %0, %1, %2.. 这种参数变量,还可以扩展一下变量:

语法:

%~[flag]num

num 是第几个参数,如 0,1,2,...

flag 是可选项,有如下几种,并且可以组合一起:

  • d : 获取驱动器号
  • f : 文件路径
  • p :文件夹路径
  • n :文件名(不带后缀)
  • x :后缀名
  • s :文件路径的短名
  • a :文件属性
  • t :文件修改日期和时间
  • z :文件大小
  • $PATH :查找环境变量中的路径
  • dp:获取驱动器和路径
  • nx :获取文件名和后缀
  • ftza :文件的路径,时间,大小等信息,类似于 dir 命令的输出

flag 如果不写,则去除参数的引号,如果不知道路径带不带引号,用它非常有用。

实例:

test script.bat

@echo off

:: 处理 %0 这个变量
echo 删除引号: %~0
echo 扩充到路径: %~f0
echo 扩充到一个驱动器号: %~d0
echo 扩充到一个路径:%~p0
echo 扩充到一个文件名: %~n0
echo 扩充到一个文件扩展名: %~x0
echo 扩充的路径只含有短名: %~s0
echo 扩充到文件属性: %~a0
echo 扩充到文件的日期/时间: %~t0
echo 扩充到文件的大小: %~z0
echo 查找列在 PATH 环境变量的目录,并将第一个参数扩充到找到的第一个完全合格的名称: %~$PATH:0
echo 扩展到驱动器号和路径: %~dp0
echo 扩展到文件名和扩展名: %~nx0
echo 扩展到类似 DIR 的输出行: %~ftza0 

pause & exit

双击运行,输出:

删除引号: C:\Users\wztshine\Desktop\test script.bat
扩充到路径: C:\Users\wztshine\Desktop\test script.bat
扩充到一个驱动器号: C:
扩充到一个路径:\Users\wztshine\Desktop\
扩充到一个文件名: test script
扩充到一个文件扩展名: .bat
扩充的路径只含有短名: C:\Users\wztshine\Desktop\test script.bat
扩充到文件属性: --a--------
扩充到文件的日期/时间: 2022/05/19 16:29
扩充到文件的大小: 514
查找列在 PATH 环境变量的目录,并将第一个参数扩充到找到的第一个完全合格的名称: C:\Users\wztshine\Desktop\test script.bat
扩展到驱动器号和路径: C:\Users\wztshine\Desktop\
扩展到文件名和扩展名: test script.bat
扩展到类似 DIR 的输出行: --a-------- 2022/05/19 16:29 514 C:\Users\wztshine\Desktop\test script.bat
请按任意键继续. . .

标签:文件,bat,set,批处理,cmd,echo,%%,pause,txt
来源: https://www.cnblogs.com/wztshine/p/16295775.html