bat学习与简单实践

bat学习与简单实践

1.概念

.bat在 Windows 系统下是一种可执行文件。我们可以在这种文件中输入一系列的 DOS 命令,来自动地执行某些指令。带 .bat、.cmd 后缀的文件是批处理文件。bat 全称:batch 。


批处理,也称批处理脚本,就是对某对象进行批量的处理,通常被认为是一种简化的脚本语言,它应用于 DOS 和 Windows 系统中。批处理文件的扩展名为 bat 或 cmd。比较常见的批处理包含两类:DOS 批处理和 PS 批处理。

一些有关于批处理学习的文档地址:http://www.bathome.net/index.php

2.特殊符号

2.1.@ 隐藏命令

隐藏 @ 后的命令,不让命令在终端输出。

不加“@”:

1
2
echo lala
pause>nul

执行结果:



加“@”:

1
2
@echo lala
pause>nul

2.2.&&和||判断

这两个符号拼接的命令属于组合命令。&拼接的也属于组合命令。

&&表示前面的命令成功就执行后面的命令,||反之。

1
2
3
@echo off
@echo;>>D:\code\study\bat\test.txt&&echo success||echo failed
pause>nul

目录:

执行结果:

2.3.管道

2.3.1 |

它能够将它右边命令的输入后果放到它左边的命令里作为输出参数。

1
2
3
@echo hello1 | find "ll"
@echo hello2 | find "aa"
@pause>nul

执行结果:


2.3.2 >、>>、< 重定向符

DOS 的标准输入输出通常是在标准设备键盘和显示器上进行的,利用重定向可以方便将输入输出改向磁盘文件或者其它设备。

2.3.2.1 >

>:将命令发送到文件或者设备(有些命令输出重定向,比如错误信息)

原来:

1
2
3
@echo off
type aa.txt>bb.txt
pause>nul

执行结果:

2.3.2.2 >>

>>:将命令输出添加到文件结尾,而不删除文件中已有的内容

原来:

1
2
3
@echo off
type aa.txt>>bb.txt
pause>nul

执行结果:

2.3.2.3 <

<:从文件而不是键盘上获取命令所需的输入

1
2
3
4
@echo off
set /p var="" < aa.txt
echo %var%
pause>nul

执行结果:

2.4.& 分行符

可以把几个命令写在同一行。属于组合命令。

1
2
@echo 123&@echo 456
@pause>nul

执行结果:

2.5.^ 分行与转义符

2.5.1.分行

可以把一个命令写成多行。

1
2
3
4
5
@echo 1^
2^
3^
4
@pause>nul

执行结果:

2.5.1.转义

将特殊符号转变为普通字符串。譬如“&”是特殊符号,可以对“&”转义输出:

1
2
@echo ^&
@pause>nul

执行结果:

2.6.通配符

*: 匹配任意字符,个数不限。

?: 只匹配一个任意字符。

下文中的“ for 语法介绍”这一章节有例子。

2.7.括号

括号,在批处理编程中有特殊的作用,左右括号必须成对使用,括号中可以包括多行命令,这些命令将被看作一个整体,视为一条命令。

括号在 for 语句或者 if 语句中常见,用来嵌套使用循环或者条件语句,其实括号也可以单独使用。

以下两段代码等价:

1
echo 1 & echo 2 & echo 3

等价于:

1
2
3
4
5
(
echo 1
echo 2
echo 3
)

3.变量

3.1.类型

批处理中的变量基本是万能的,可以储存各种各样的数据。不过用来计算时,会发现变量类型转为了int(整数),数值的极端范围为[-2147483648,2147483647],如果不拿来计算的话,似乎数万位也是可以的。

3.2.命名

变量名可以为数字、字母、甚至汉字的组合。
平时尽量不要用命令、汉字取名。不能直接用数字作为变量名。建议直接用非关键字的单词来命名变量。

3.3.扩展

先看以下代码:

1
2
3
4
@echo off
set var1=1
echo var1
pause > nul

执行结果:

第3行语句执行时,直接打印了变量名。如果想要引用变量的值,就需要做一些扩展。比如我定义了一个变量等于一个计算结果,我想打印出来这个变量,那么我就需要对这个变量进行扩展。

扩展的方式有两种:%变量% 或 !变量!

!变量! 这种变量与延迟环境变量扩展有关。如果没开启延迟环境,那么!var!就是一个普通的包含5个字母的字符串。如果开启了延迟环境变量扩展,那么它就是变量的实际值。开启延迟环境变量扩展,语句为“SetLocal EnableDelayedExpansion”。

对比下两种扩展:

1
2
3
4
5
@echo off
set num=10
echo %num%
set num=100&echo %num%
pause>nul

执行结果:

你或许会奇怪,为啥第 4 行语句中 变量 num 已经赋值为 100 了,打印出来还是 10 呢?这跟批处理脚本执行机制有关。批处理脚本是按行执行,执行前会先预处理。第4行语句的 num 在预处理的时候,%num% 被替换成 10 了,实际执行到的语句是:“set num=100&echo 10”,所以打印成了 10。针对这种情况,我们需要开启延迟环境变量扩展,使用 !变量!+SetLocal EnableDelayedExpansion 的一套语法:

1
2
3
4
5
6
@echo off
SetLocal EnableDelayedExpansion
set num=10
echo !num!
set num=100&echo !num!
pause>nul

执行结果:

在 for 循环中要格外注意,因为 for 循环语句的循环体括号中,所有的操作被看成是同一行。所以经常会用到延迟环境变量扩展。

其他说明

  1. 可以直接用 %time% 获取到当前系统时间。
1
2
3
@echo off
echo %time%
pause>nul

执行结果:

3.4.字符串的处理

假设变量 str 值为“1234567890”:

3.4.1.截取字符串

格式 含义 结果
%str% 获取整个字符串的值 1234567890
%str:~0,5% 从索引值0开始,截取5个字符 12345
%str:~1,5% 从索引值1开始,截取5个字符 12345
%str:~-5% 从字符串末尾开始,截取5个字符 67890
%str:~5,-2% 从索引值5开始,截取到倒数下标为2个字符 678

3.4.2.替换字符串

语法:%变量:子字符串=被替换的字符串%

1
2
3
4
@echo off
set str=1234567890
echo %str:7890=54321%
pause>nul

执行结果:

3.4.3.合并字符串

语法:%变量1%%变量2%

1
2
3
4
5
6
@echo off
set str1=a
set str2=b
set str3=str3=%str1%%str2%
echo %str3%
pause>nul

执行结果:

3.4.4.字符串修饰符

设变量为i:

修饰符 含义
~i 删除所有引号(”)
%~fi 将 %Ii扩充到一个完全合格的路径名
%~di 仅将 %i 扩充到一个驱动器号
%~pi 仅将 %i 扩充到一个路径
%~ni 仅将 %i 扩充到一个文件名
%~xi 仅将 %i 扩充到一个文件扩展名
%~si 扩充的路径只含有短名
%~ai 将 %i 扩充到文件的文件属性
%~ti 将 %i 扩充到文件的日期/时间
%~zi 将 %i 扩充到文件的大小
%~$PATH:i 查找列在路径环境变量的目录,并将 %i 扩充到找到的第一个完全合格的名称。如果环境变量名未被定义,或者没有找到文件,此组合键会扩到空字符串

也可以组合地使用多个修饰符,比如想要将 %i 扩充到一个驱动器号和路径,可以写成 %~dpi 。

4.命令

以下命令大写小写都行。命令执行优先级:管道命令 > 重定向命令 > 组合命令

echo

用途:在命令行编辑器中打印一些文字。

语法:

echo [on | off]

echo [message]

echo [%变量名%]

执行 echo on 后,后来执行的指令不会把命令回显出来,直接打印文字。反之 echo off 会把命令显示出来,并打印文字。echo xxx 就会直接打印 xxx。

执行代码感受下:

1
2
3
4
5
6
7
echo off
echo aaa
echo bbb
echo on
echo aaa
echo bbb
pause

执行结果:

echo [%变量名%]在介绍 set 命令的时候会有示例。

其他用法

  1. 换行
1
echo;
  1. 输出空行

echo.输出一个空行,这里的.和 echo 之间不要有空格,其实除了echo.有这个效果,echo+echo-echo*echo,都可以。
3. 输出 off、on 关键字

1
2
3
4
@echo off
echo;off
echo;on
pause > nul

pause

用途:暂停让用户按下任意键继续。

语法:

  1. pause


  2. pause > nul
    不展示“请按任意键继续…”的文本,用户按下任意键结束。

cls

清屏。

rem

用途:在批处理文件或 CONFIG.SYS 里加上注解或说明。注解和说明不会被打印出来。

语法:rem [comment]

给下一行代码添加注释的示例:

1
2
3
4
echo off
rem 打印文字
echo lala~
pause

set

用途:

1、给变量赋值;

2、等待用户输入数据(开关/P);

1、给变量赋值

语法:set 变量名 =xxx
变量名相同时,后边声明的会覆盖前边声明的。

示例:

1
2
3
4
@echo off
set str= lalala~ 打断点
echo %str%
pause

里注意了,变量赋值的时候,变量与等号之间不能有空格,不然会赋值失败。等号后边的所有内容都会赋给变量。赋值时输入中文会乱码。遇到回车相当于语句结束。以上代码的执行结果为:


运算在第3小节介绍。

给变量赋值还能撤销(目前还不知道什么情况下要撤销)给变量赋值直接让等号后边不跟任何内容就行了:

1
2
3
4
5
6
@echo off
set str=yyds
echo %str%
set str=
echo %str%
pause

2、等待用户输入数据

语法:set /p 变量名=xxx

1
2
3
4
5
@echo off
set /p name=input your name:
set /p age=input your age:
echo %name% is %age% years old.
pause

3、计算

语法:set /a 变量名=表达式

注意:批处理能处理的数字必须是整数,不能是小数。可处理的数据范围:[-2147483648,2147483647]。

1
2
3
4
@echo off
set /a num=(12*2)+(13*4)
echo (12x2)+(13x4)=%num%
pause

我们来看一个获取平方数的例子:

1
2
3
4
5
6
7
@echo off
echo ===Get Square===
set /p num=input number:
echo you inputed number is %num%.
set /a num*=num
echo result is %num%.
pause

set /a支持多行表达式并列,比如:

1
set /a num1=1+1,num2=1+2,num3=1+3

若是想计算小数,我们需要将小数扩大到10的 n 倍,让其成为整数计算,在使用时可以用字符串截取、字符串拼接的语法转成小数。

若是计算的数值想保留到几位小数,我们以除法为例,举了一个四舍五入的例子:

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
chcp 65001
@echo off
title 被除数的数字位和精确位数和不能大于10
setlocal enabledelayedexpansion
set 零常数=100000000000000000000000000000000
:整数
cls
set /p 被除数=被除数:
set /p 除数=除数:
set /p 精确位数=精确到多少小数点(遇用于小数时):
set /a 解=!被除数!/!除数!
set /a x=!解!*!除数!
cls
if !x!==!被除数! (
echo !被除数!/!除数!=!解!
pause>nul
goto 整数
)
:小数
set/a 精确位数加一 =%精确位数%+1
set 数点=!零常数:~-%精确位数加一%!
set x=!被除数!!数点!
set /a 小解=!x!/!除数!
set 最后一位=!小解:~-1!
echo !最后一位!
rem 四舍五入
if !最后一位! gtr 5 (
set /a 小解=!x!/!除数!+1
)
set 小数=!小解:~-%精确位数%!
set 解=!解!.!小数!
echo !被除数!/!除数!=!解!
pause>nul
goto 整数

4.显示当前已定义变量

以下示例可直接输出当前所有的系统变量:

1
2
@set
@pause>nul

在@set 后边还可加上过滤条件(不区分大小写):

1
2
@set al
@pause>nul

上例执行结果:


if

语法:
if 表达式 (

执行语句

) else if 表达式 (

执行语句

) else (

执行语句

)

1.比较字符串

语法:

if %变量名% == 字符串 (执行语句)

if “%变量名%” == “字符串” (执行语句)

1
2
3
4
5
6
7
8
9
10
@echo off
set /p name=please input string:
if %name% == aa (
echo aaa
) else if %name% == bb (
echo bb
) else (
echo emmm...
)
pause>nul

如果想判断是否输入了回车,需要加上双引号来判断(if “%name%” == “aa”),否则直接输入回车就会关闭命令行。

2.比较数字

语法:if %变量名% 比较运算符 %变量名% (执行语句)

需要了解下比较运算符:

比较运算符
EQU | equ - 等于
NEQ | neq - 不等于
LSS | lss - 小于
LEQ | leq - 小于或等于
GTR | gtr - 大于
GEQ | geq - 大于或等于

比较数字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@echo off
set /p num1=please input num1:
set /p num2=please input num2:

rem 若num1 > num2
if %num1% gtr %num2% (
echo num1 bigger than num2
rem 若num1 < num2
) else if %num1% lss %num2% (
echo num1 less than num2
rem 若num1 < num2
) else (
echo num1 equal num2
)

rem 若num1 !== num2 not 为可选值,表示非
if not %num1% equ %num2% (
echo 666
)

pause>nul

3.检测文件(夹)是否存在

该命令可用来判断文件是否存在,并执行相关的命令。语法见示例:

语法1:

if exist 文件名 文件存在执行的命令

if not exist 文件不存在执行的命令

示例:

1
2
3
4
@echo off
if exist a.txt type a.txt
if not exist a.txt echo a.txt isn't exist.
pause > nul

type 是 DOS 命令。type 文件名,表示将一个文件的内容输出到命令行中。详细介绍:https://baike.baidu.com/item/type/61894579?fr=ge_ala


语法2:

if exist 命令传参 文件存在执行的命令

if not exist 文件不存在执行的命令

DOS 允许传递 9 个批参数信息给批处理文件,分别为 %1~%9(%0表示命令本身)。%1表示的是第一个传参,%2 表示的是第二个传参,以此类推。

下例中,我们在当前目录中新建了c.txt,c.txt的内容:。然后在当前目录创建 if-exist.bat,添加以下代码块的内容:

1
2
3
4
@echo off
if exist %1 type %1
if not exist %1 echo %1 isn't exist.
pause > nul

然后在当前目录打开命令行,输入if-exist c.txt,“c.txt”就是 if-exist.bat 实参 %1 的值了。运行结果:


4.检测变量是否被定义

语法:if defined 变量名 (执行语句)

检测变量是否被定义:

1
2
3
4
5
6
7
8
@echo off
set aa=a
if defined aa (
echo aa has defined.
) else (
echo aa haven't defined.
)
pause>nul

5.判断返回值(errorlevel)

语法:

批处理命令

if errorlevel 返回值 (执行语句)

用来测试它的上一个 DOS命令 的返回值。注意只是上一个命令的返回值,而且返回值必须依照从大到小次序顺序判断。

注:这里的执行语句最好使用 goto 语句,不然的话会执行剩下的 if errorlevel语句。这里可以看一个示例:

1
2
3
4
5
6
7
@echo off
copy D:\code\study\bat\c.txt D:\code\study\bat\b
if errorlevel 1 echo failed
if errorlevel 0 echo success
if errorlevel -1 echo 1111
if errorlevel -2 echo 222
pause > nul

若 c.txt 不存在,执行结果:


若 c.txt 存在,执行结果:


执行到第4条语句后,语句4、5、6因为上一条语句返回值是1,所以也都挨个触发了。

我们来看正确的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
@echo off
copy D:\code\study\bat\c.txt D:\code\study\bat\b
if errorlevel 1 echo goto error
if errorlevel 0 echo goto success
:error
echo error
pause > nul
exit

:success
echo success
pause > nul
exit

若 c.txt 存在,执行结果:


若 c.txt 不存在,执行结果:


如果不想展示命令执行输出的结果(如上图的),可以在 copy 语句后加上 >nul 2>nul:

1
copy D:\code\study\bat\c.txt D:\code\study\bat >nul 2>nul

copy 是 DOS命令,作用是拷贝文件。格式:copy [源目录或文件] [目的目录或文件]

注意:在该示例中,if errorlevel 1 表示命令执行结果失败的判断,if errorlevel 0 表示命令执行结果成功的判断。这两行命令不能调换位置。

一些常用 DOS 命令的返回值:

命令名 返回值 含义
xcopy 0 成功拷贝文件
xcopy 1 未找到拷贝文件
xcopy 2 用户通过ctrl-c中止拷贝操作
xcopy 4 预置错误阻止文件拷贝操作
xcopy 5 拷贝过程中写盘错误
format 0 格式化成功
format 3 用户通过ctrl-c中止格式化处理
format 4 因致命的处理错误使格式化中止
format 5 在提示“proceed with format(y/n)?”下用户键入n结束
backup 0 备份成功
backup 1 未找到备份文件
backup 2 文件共享冲突阻止备份完成
backup 3 用户用ctrl-c中止备份
backup 4 由于致命的错误使备份操作中止

%errorlevel%能获取到上一条语句的返回值。

1
2
3
4
@echo off
copy D:\code\study\bat\test.txt D:\code\study\bat\b
echo %errorLevel%
pause>nul

执行结果:

goto

语法:goto label


label为标签名。标签必须独占一行,并以冒号打头。例:

:label1


未定义的:eof会退出脚本文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@echo off
set /p pw=please input string:
if "%pw%"=="lala" goto yes
if "%pw%"=="a" goto error
goto :eof
rem 未定义的:eof会退出脚本文件

:error
echo error
pause>nul

:yes
echo ture
pause>nul

输入“lala”,会打印:

输入a,会打印:

输入ccc,会关闭窗口。

注意:多个标签的情况下,注意是否需要在标签间添加退出语句来终止脚本继续向下执行,若不往下进行则要在最后加上 exit 命令退出当前标签。

加上exit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@echo off
set /p pw=please input string:
if "%pw%"=="lala" goto yes
if "%pw%"=="a" goto error
goto :eof
rem 未定义的:eof会退出脚本文件

:error
echo error
pause>nul
exit

:yes
echo ture
pause>nul
exit

输入a,会打印:

for

说明:下文语法中的 set 表示一个集合,每个元素以空格分隔,如(a b)。do 后面的语句会被执行。

语法1:for %variable in (set) do command [command-parameters]

%variable 指定一个单一字母可替换的参数。

(set) 指定一个或一组文件。可以使用通配符。

command 指定对每个文件执行的命令。

command-parameters为特定命令指定参数或命令行开关。

注: %%i为for输出专用变量格式,其中i可以是a-z、A-Z、0-9和一些符号什么的(如! # 不过不建议使用),在cmd中只能用一个%。

1
2
3
@echo off
for %%i in (a b c) do echo %%i
pause>nul

打印结果:

展示当前目录下所有带.txt后缀的文件名:

1
2
3
@echo off
for %%i in (*.txt) do echo %%i
pause>nul

打印结果:


语法2:for /l %variable in (start,step,end) do command [command-parameters]

该集表示以增量形式从开始到结束的一个数字序列。

1
2
3
@echo off
for /l %%i in (1,2,10) do echo %%i
pause>nul

打印结果:

语法3:for /r [[drive:]path] %variable in (set) do command [command-parameters]

检查以 [drive:]path 为根的目录树,指向每个目录中的 for 语句。如果在 /r 后没有指定目录,则使用当前目录。如果集仅为一个单点 (.) 字符,则枚举该目录树。

1
2
3
@echo off
for /r D:\code\study\bat %%i in (*) do echo %%i
pause>nul

打印结果:

语法4:for /d [[drive:]path] %variable in (set) do command [command-parameters]

如果集中包含通配符,则指定与目录名匹配,而不与文件名匹配。

1
2
3
@echo off
for /d %%i in (*) do echo %%i
pause>nul

执行结果:

语法5:for /f [“options”] %variable in (文件名|”字符串”|’命令名’) do command [command-parame]

按行输出。test.txt 写入了两行内容,但是只能遍历出空格之前的内容。

1
2
3
4
5
6
@echo off
echo aa bb cc>>test.txt
echo dd ee>>test.txt
rem 以上代码在当前文件夹下生成了一个test.txt,打开看看?
for /f %%i in (test.txt) do echo %%i
pause>null

test.txt:

打印结果:

“options”可以有以下参数:

参数 含义
“token=1” 取当前行的第1个元素(默认情况下,一行字符串按空格分隔成集合)
“token=*” 取当前行的所有元素
“delims=*” 设置元素的分隔符为任意字符,即会获取到整行字符串
“skip=1” 忽略文本的前1行,若文本中一行内容都没有则什么也不输出
“eol=a” 忽略以a开头的行

在下例中, aa bb cc 可以看做一个集合,元素为aa、bb、cc,以空格分隔。

可以理解为:遍历某个文件中的每一行,一次遍历一行,取到集合中的第几个元素%%i,进行操作。

1
2
3
4
5
6
7
8
9
@echo off
echo aa bb cc>>test.txt
echo dd ee>>test.txt
for /f "tokens=1" %%i in (test.txt) do echo %%i
pause>nul
for /f "tokens=2" %%i in (test.txt) do echo %%i
pause>nul
for /f "tokens=3" %%i in (test.txt) do echo %%i
pause>nul

test.txt:

打印结果:

第一次循环结束打印:,回车

第二次循环结束打印:,回车

第三次循环结束打印:

还有很多可扩展变量的修饰符。比如对循环遍历一组目录路径,想在每一次遍历时取到路径中的驱动器号,假设循环中定义的变量为 %i,则可以写成 %~di 。

1
2
3
@echo off
for /f %%i in (a.txt) do echo %%~di
pause>nul

a.txt 内容:

执行结果:

关于字符串修饰符可见这一章节:3.4.4 字符串修饰符

start

start 命令可以在命令行下运行一个程序,可以打开盘符,文件,文件夹,网址,程序。该外部程序在新的窗口中运行,批处理程序继续往下执行,不理会外部程序执行的情况),如果直接运行外部程序则必须等待外部程序完成后才可以继续执行剩余的指令。

打开网址:

1
2
3
@echo off
start www.baidu.com
pause>nul

打开文件:

1
2
3
@echo off
start "" "D:\software\Robo 3T 1.4.1\robo3t.exe"
pause>nul

注: 路径中有空格时,不仅路径要加双引号,路径之前也要加(路径之前的空双引号表示空标题)

打开文件夹:

1
2
3
@echo off
start "" "D:\software\Robo 3T 1.4.1"
pause>nul

打开盘符:

1
2
3
@echo off
start d:
pause>nul

start cmd.exe启动参数说明

用的比较多的:

1、start cmd /k “命令”

表示启动一个CMD且不关闭cmd

2、start cmd /c “命令”

表示启动一个CMD且关闭cmd

更多启动参数详见:https://blog.csdn.net/chenghui2006/article/details/108363769

5.一些简单实践

5.1 开机自启动项目

创建一个start.bat,内容如下:

1
2
3
4
5
:: 运行mapgo5.0项目

d:
cd "D:\code\company-silu\infrastructure\map-go\map-go2.0"
npm run serve

win+r 打开运行,输入 shell:startup,打开开机自执行脚本的目录,将 start.bat 放到目录下。

这样,你每天一开机,去打个水上个厕所的功夫,你的前端项目就自己启动起来啦~是不是很实用?

5.2 快速启动所有主应用微应用

启动一堆主应用微应用太费事?写一个批处理命令文件,只需双击两下,就能搞定一切~

1
2
3
@echo off
start cmd /k "d: && cd D:\code\company-silu\pwxkz-manage-servie-production\baseapp && npm run serve"
start cmd /k "d: && cd D:\code\company-silu\pwxkz-manage-servie-production\microapp && npm run serve"

6.其他

6.1.自动运行批处理文件 AUTOEXEC.BAT

6.2.让批处理脚本支持汉字

默认情况下,cmd.exe 的编码是 GBK 编码:。要想显示中文汉字不乱吗,需要将编码改成 UTF-8编码的(65001)。

我们可以在.bat文件首行加上“chcp 65001”,就能正常使用汉字啦。

1
2
3
chcp 65001
echo test中文
pause>nul

执行结果:

作者

吕芷欣

发布于

2023-08-05

更新于

2023-08-13

许可协议

CC BY-NC-SA 4.0

评论