0%

Batch 脚本基础

基本语法

set 设置变量

作用:显示、设置或删除环境变量。

1
2
3
set [<Variable>=[<String>]]
set [/p] <Variable>=[<PromptString>]
set /a <Variable>=<Expression>

Variable 指定环境变量名,String 表示指派给变量的字符串。

注意:= 前不能有空格,否则无法设置变量。后面可以有空格,但是空格包含在字符串内,例如:set p=abcp 的值为 abcset p= abcp 的值为 _abc(下划线表示空格)。

基础用法

  • set , 显示目前所有可用的变量,包括系统变量和自定义的变量。
  • set p,显示所有以 p 开头的变量,要是一个也没有的话就设 errorlevel=1
  • set p=abcdefgh,设置变量 p,并赋值为 = 后面的字符串,即 abcdefgh
  • set /a p=42,设置 p 为数值型变量,值为 42
  • set /a p=42/10,支持运算符,运算后取整,p=42/10=4.2=4
  • set p=,取消 p 变量。
  • set /p p=,将变量的值设置为用户输入的输入行。
  • set /p p=input:,在屏幕上显示 input:,并将用户输入行作为 p 的值。

变量的引用即赋值

例,设有 set p=abcdefgh

  • echo %p%,显示 p 的值,即 abcdefgh
  • echo %p:~3%,显示 p 的第 3 个字符以后的所有字符,即 defgh
  • echo %p:~3,3%,显示 p 的第 3 个字符以后的 3 个字符,即 def
  • echo %p:~0,3%,显示 p 的前 3 个字符,即 def
  • echo %p:~-2%,显示 p 的最后 2 个字符,即 gh
  • echo %p:~0,-2%,显示 p 的第 1 个字符到最后 2 个字符之前的所有字符,即 abcdef
  • echo %p:a=i%,将 p 中的 a 替换为 i,即 ibcdefgh
  • echo %p:b=%,将 p 中的 b 替换为空,即 acdefgh
  • echo %p:*cd=j%,将 p 中的 cd 及之前的字符替换为 j ,即 jefgh
  • set q=%p:*e=k%,将 p 中的 e 及之前的字符替换为 k 并设置为变量 qq 的值为 kfgh

常见变量

  • %CD%,代表当前目录的字符串。
  • %DATE%,当前日期。
  • %TIME%,当前时间。
  • %RANDOM%,随机整数,介于 0~32767。
  • %ERRORLEVEL%,当前 ERRORLEVEL 值。

setlocal

默认 bat 文件中的变量是全局的,也就是说在一个 bat 文件中创建的变量,在程序的任何地方都可以访问。

使用 setlocalendlocal 来设定变量的作用域,在这两个之间出现的变量属于局部变量。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@echo off
rem var是一个全局变量
set var=global

setlocal

rem var是一个局部变量
set var=local

rem 显示local
echo %var%

endlocal

rem 显示 global
echo %var%

pause

setlocal enabledelayedexpansion

批处理读取命令是按行读取,处理每行命令前会对语句做预处理,所以变量的值会在预处理时设置。有点类似于 C 语言中的宏替换。

例如:

1
2
3
4
5
set var1=foo
if "%var1%" == "foo" (
set var1=bar
echo %var1%
)

虽然使用了 set var1=bar,但是输出的还是 foo

这时开启 setlocal enabledelayedexpansion ,可以获取到变量的运行时的值,同时取变量是需要用 !var1! 来取值。

例如:

1
2
3
4
5
6
7
setlocal ENABLEDELAYEDEXPANSION
set var1=foo
if "%var1%" == "foo" (
set var1=bar
echo !var1!
)
endlocal

这时输出的值为 bar

批处理参数

批处理的参数可以用 %*%0, %1, %2...)来引用,索引 0 表示当前执行的脚本文件,索引 1 以后表示其他参数(升序)。

批处理参数 说明
%~1 展开 %1 并删除周围的引号(””)。
%~f1 %1 扩展到完全限定的路径。
%~d1 仅将 %1 扩展到驱动器号。
%~p1 仅将 %1 展开为路径。
%~n1 仅将 %1 扩展到文件名。
%~x1 仅将 %1 扩展到文件扩展名。
%~s1 %1 扩展到仅包含短名称的完全限定路径。
%~a1 %1 扩展到文件属性。
%~t1 %1 扩展到文件的日期和时间。
%~z1 %1 扩展到文件的大小。
%~$PATH:1 搜索 PATH环境变量中列出的目录,并将 %1 扩展到找到的第一个目录的完全限定名称。 如果未定义环境变量名称或搜索找不到该文件,则此修饰符将扩展为空字符串。
带有修饰符的批处理参数 说明
%~dp1 %1 扩展到驱动器号和路径。
%~nx1 仅将 %1 扩展到文件名和扩展名。
%~dp$PATH:1 搜索 %1 的 PATH 环境变量中列出的目录,然后扩展到找到的第一个目录的驱动器号和路径。
%~ftza1 展开 %1 以显示类似于 dir 命令的输出。

for 命令

语法

1
for { %%|%}<Variable> in (<Set>) do <Command>
参数 描述
`{ %% %}` Variable 变量。表示可替换参数。命令行下使用 %,批处理文件中使用 %%。变量区分大小写,必须使用字母值(例如:%A, %B, %C)。
<Set> 范围,需要括号括起来。
<Command> 在每个循环中执行的命令。

备注

  • <Set> 参数指定一组文件,可以使用通配符(*?),例如:
1
2
3
4
(*.doc)
(*.doc *.txt *.pdf)
(jan*.doc jan*.txt feb*.doc feb*.txt)
(jan??2020.* feb??2020.*)

扩展参数

  • /d,仅目录。

  • /r,遍历整个目录树,包括子目录树。如果 <Set>.,则只遍历目录。语法:

1
for /r [[<Drive>:]<Path>] {%%|%}<Variable> in (<Set>) do <Command>

假设目录为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
E:\
folder1\
subFolder1\
text.txt
subFolder2\
text.txt
folder2\
text.txt
newFolder1\
newFolder2\
text1.txt
text2.txt
word1.doc
word2.doc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# /d 显示所有以 folder 开头的文件夹
E:\> for /d %a in (folder*) do @echo a
folder1
folder2

# /r 显示所有文件
E:\> for /r . %a in (*) do @echo %a
E:\text1.txt
E:\text2.txt
E:\word1.doc
E:\word2.doc
E:\folder1\text.txt
E:\folder1\subFolder1\text.txt
E:\folder2\text.txt

# /r 显示所有文件夹
E:\> for /r . %a in (.) do @echo %a
E:\.
E:\folder1\.
E:\folder1\subFolder1\.
E:\folder1\subFolder2\.
E:\folder2\.
E:\newFolder1\.
E:\newFolder2\.
  • /l,遍历值,从起始值(Start)到结束值(End)。例如:(1,1,5) 生成 1 2 3 4 5(5 ,-1,1) 生成 5 4 3 2 1。语法:
1
for /l {%%|%}<Variable> in (<Start>,<Step>,<End>) do <Command>
  • /f,遍历文本文件中的文本。语法:
1
2
3
for /f [<ParsingKeywords] {%%|%}<Variable> in (<Set>) do <Command>
for /f [<ParsingKeywords] {%%|%}<Variable> in (<LiteralString>) do <Command>
for /f [<ParsingKeywords] {%%|%}<Variable> in ('<Command>') do <Command>

ParsingKeywords 关键字:

关键字 描述
eol=<c> 指定行尾字符(仅一个字符)。
skip=<N> 指定文件开头要跳过的行数。
delims=<xxx> 指定分隔符集。默认为i空格和制表符。
tokens=<X,Y,M-N> 指定每行的哪些标记要传递到循环中。

例子:

文件 text1.txt 内容如下:

1
2
3
4
line no 1 first
line no 2 second
row no 3 third
row no 4 fourth
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 打印 text1.txt 的内容,只打印出了第一个单词,因为默认分隔符是空格,遍历每行时只获取到第一个变量
E:\> for /f %a in (text1.txt) do @echo %a
line
line
row
row

# 设置分隔符集为空,打印所有内容
E:\> for /f "delims=" %a in (text1.txt) do @echo %a
line no 1 first
line no 2 second
row no 3 third
row no 4 fourth

# 使用 M,N,表示第 M 和 第 N 个标记,不限于2位,可以 M,N,O,P 表示多个标记。
# 例如:打印出第3 4个
E:\> for /f "tokens=3,4" %a in (text1.txt) do @echo %a,%b
1,first
2,second
3,third
4,fourth

# 使用 M-N,表示第 M 到第 N 个标记。
# 例如:打印出 1-3 之间
E:\> for /f "tokens=1-3" %a in (text1.txt) do @echo %a,%c
line,1
line,2
row,3
row,4

# 使用 * 星号,代表之后的范围。
# 例如:打印出第 3 个标记以后的
E:\> for /f "tokens=3*" %a in (text1.txt) do @echo %a,%b
1,first
2,second
3,third
4,fourth

其他

获取路径

常用变量

  • %cd%,当前执行脚本的目录路径。
  • %~d0,脚本文件所在的盘符。
  • %~dp0,脚本文件所在的目录路径。
  • %~df0,脚本文件的文件路径。
  • %0,脚本文件的文件路径字符串,比 %~df0% 多了引号。
  • %~0,同 %~df0

其他可参见:批处理参数

例:文件结构如下:

1
2
3
4
D:
- dirA # 文件夹dirA
- dirB # 文件夹dirB
- test.bat # bat文件

test.bat 文件内容如下

1
2
3
4
5
6
7
@echo off
echo %cd%
echo %~d0
echo %~dp0
echo %~df0
echo %0
echo %~0

D:\dirA 目录下执行 test.bat 文件:

1
D:\dirA>test.bat

输出结果为:

1
2
3
4
5
D:\dirA
D:
D:\dirB\
D:\dirB\test.bat
"D:\dirB\test.bat"

获取文件夹、文件名、不带扩展名的文件名。

1
2
3
4
5
6
7
8
9
set filepath="C:\some path\having spaces.txt"

for /F "delims=" %%i in (%filepath%) do set dirname="%%~dpi"
for /F "delims=" %%i in (%filepath%) do set filename="%%~nxi"
for /F "delims=" %%i in (%filepath%) do set basename="%%~ni"

echo %dirname%
echo %filename%
echo %basename%

中文乱码

  • 方法一:将 bat 文件存为 ANSI 编码
  • 方法二:在文件开始声明编码
1
2
rem 声明采用UTF-8编码
chcp 65001

参考链接