CMD(BAT)基本语法及批量拉取代码BAT

基本语法

变量定义与使用

在 cmd 中,要设置一个变量,可以使用 set 命令,语法如下:

1
set 变量名=变量值

例如,要设置变量名为 my_var 的变量,值为 hello world,可以这样写:

1
set my_var=hello world

要使用这个变量,可以使用 % 符号将变量名包含起来,例如:

1
echo %my_var%

这会输出变量 my_var 的值 hello world。可以在需要使用这个变量的地方使用 %my_var% 代表该变量的值。

创建文件夹

1
IF NOT EXIST "_dist" mkdir "_dist"

移动文件或文件夹

1
move "z-wiki" "_dist/"

复制文件

这个只会复制一层

1
copy "web" "_dist/"

复制文件夹

1
xcopy /e /i "web" %TARGET_DIR_PATH%web

注意

后面也要写文件夹名,否则不会创建文件夹

调用子程序

默认BAT调用程序,程序退出,BAT不会继续执行,会退出。

使用call调用就会继续执行。

1
call npm run build

不打印日志

1
call npm run build > NUL

查找字符串

方式1

1
2
3
4
5
@echo off 
set str=machine-order-service
echo %str% | findstr order >nul && echo yes || echo no
echo %str% | findstr orderd >nul && echo yes || echo no
pause

方式2

1
2
3
4
5
6
7
8
9
@echo off  
set str=0pass
echo %str%|findstr "pass" >nul
if %errorlevel% equ 0 (
echo ok
) else (
echo not ok
)
pause

for循环中

在for循环中 方式1依旧生效

1
2
3
4
5
6
7
@echo off  
set MYPATH=%cd%
for /d %%a in (%MYPATH%\*) do (
echo %%a
echo %%a|findstr "pass" >nul && echo yes || echo no
)
pause

方式2则需要改成如下才能生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@echo off  
setlocal EnableDelayedExpansion

set MYPATH=%cd%
for /d %%a in (%MYPATH%\*) do (
echo %%a
echo %%a|findstr "pass" >nul
if !errorlevel! equ 0 (
echo ok
) else (
echo not ok
)
)
pause

setlocal EnableDelayedExpansion到脚本的开头,然后使用!errorlevel!而不是%errorlevel%

注意

延迟扩展将导致变量在执行时扩展 时间而不是解析时间

延迟变量

1
setlocal EnableDelayedExpansion

设置本地为延迟扩展。其实也就是:延迟变量,全称延迟环境变量扩展, 想进阶,变量延迟是必过的一关!所以这一部分希望你能认真看。

为了更好的说明问题,我们先引入一个例子。
例1:

1
2
3
4
@echo off 
set a=4
set a=5&echo %a%
pause

结果:4
解说:为什么是4而不是5呢?在echo之前明明已经把变量a的值改成5了?

让我们先了解一下批处理运行命令的机制:

批处理读取命令时是按行读取的(另外例如for命令等,其后用一对圆括号闭合的所有语句也当作一行),在处理之前要完成必要的预处理工作,这其中就包括对该行命令中的变量赋值。

我们现在分析一下例1,批处理在运行到这句set a=5&echo %a%之前,先把这一句整句读取并做了预处理——对变量a赋了值,那么%a%当然就是4了!(没有为什么,批处理就是这样做的。)

而为了能够感知环境变量的动态变化,批处理设计了变量延迟。

简单来说,在读取了一条完整的语句之后,不立即对该行的变量赋值,而会在某个单条语句执行之前再进行赋值,也就是说延迟了对变量的赋值。

例2:

1
2
3
4
5
@echo off 
setlocal enabledelayedexpansion
set a=4
set a=5&echo !a!
pause

解说:由于启动了变量延迟,得到了正确答案。变量延迟的启动语句是setlocal enabledelayedexpansion,并且变量要用一对叹号“!!”括起来(注意要用英文的叹号),否则就没有变量延迟的效果。

分析一下例2,首先setlocal enabledelayedexpansion开启变量延迟,然后set a=4先给变量a赋值为4,set a=5&echo !a! 这句是给变量a赋值为5并输出(由于启动了变量延迟,所以批处理能够感知到动态变化,即不是先给该行变量赋值,而是在运行过程中给变量赋值,因此此时a的值就是5了)。

for循环

1
2
3
4
@echo off 
setlocal enabledelayedexpansion
for /l %%i in (1,1,5) do (set a=%%i echo !a!)
pause

结果:12345

解说:本例开启了变量延迟并用!!将变量扩起来,因此得到我们预期的结果。

如果不用变量延迟会出现什么结果呢?

结果是这样的:

ECHO 处于关闭状态。ECHO 处于关闭状态。ECHO 处于关闭状态。ECHO 处于关闭状态。ECHO 处于关闭状态。

即没有感知到for语句中的动态变化。

写入文件

基本用法

1
echo 123>test.txt

追加写入

1
echo 123>>test.txt

写入并追加

1
2
echo #!/bin/bash>test.sh
echo echo hello word>>test.sh

如果字符串中有表达式,我们需要这样写

1
echo "echo 123">test.txt

这样虽然能正常写入了,但是写入的文本内容也会被加上双引号,如下

1
"echo 123"

但是上面的写法最后都会自动添加换行或者有双引号

要想不换行可以这样写

如果文本内容中包含空格或特殊字符,需要使用双引号括起来,可以在echo后面加上 set /p 切换到提示模式来避免直接输出双引号:

1
2
<nul set /p =" hello word:">test.txt
<nul set /p =" 你好 世界 ">>test.txt

这样虽然不换行 也没有双引号了,但是前面的空格也被去掉了。

删除文件

只会删除文件,不会删除文件夹

1
del %cd%\public\* /s /q

其中

  • %cd% 是当前目录。
  • /s 删除文件和子文件夹下的文件。
  • /q 静默删除,不提醒。

删除文件夹下的文件和文件夹,不删除当前文件夹

1
del %cd%\public /s /q

删除文件夹

这个命令只能删除文件夹 后边传的路径只能是文件夹路径

1
rd /S /Q %cd%\public

其中

  • %cd%是当前目录。
  • /S rd命令只能删除空文件夹,添加\S才能删除非空文件夹。
  • /Q 静默删除,不提醒。

常见问题

注意一个大坑

在使用Bat生成sh文件的时候

注意下面一个示例

1
2
echo #!/bin/sh >test.sh
echo pwd>>test.sh

这么一个简单的脚本在服务器上运行的时候竟然无法运行

原因竟然是执行的命令最后的符号是\r,导致命令无法执行。

解决方法很简单

命令后面添加一个空格就行了,这个问题排查了很长时间,网上也没找到解决方案。

如果最终我们运行的是一个类的话,也会提示无法找到或加载主类,就很离谱。

修改后的如下

1
2
echo #!/bin/sh >test.sh
echo pwd >>test.sh

GO项目一键打包

build_linux64.bat

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
@echo off  
set TARGET_DIR=_dist
set TARGET_DIR_PATH=%cd%\%TARGET_DIR%\

echo Delete Origin Dir
IF EXIST %TARGET_DIR_PATH% rd /S /Q %TARGET_DIR_PATH%
IF NOT EXIST %TARGET_DIR% mkdir %TARGET_DIR%

echo ---------------------------------
echo Build API
set GOOS=linux
set GOARCH=amd64
set CGO_ENABLED=0
go build

echo Copy API
move "z-wiki" %TARGET_DIR_PATH% > NUL
xcopy /e /i "config" %TARGET_DIR_PATH%config > NUL

echo ---------------------------------
echo Build WEB
cd "z-wiki-web"
call npm run build > NUL
cd ..

echo Copy WEB
xcopy /e /i "web" %TARGET_DIR_PATH%web > NUL
move %TARGET_DIR_PATH%web\config_release.js %TARGET_DIR_PATH%web\config.js > NUL

echo ---------------------------------
echo Success

pause

一键拉取代码

如果我们的项目比较多,需要一个一个更新代码,我们只能一个目录进入来pull,太麻烦了,这里提供一个一键拉取代码的脚本。

支持当前同级目录项目及子目录项目的拉取更新。

pull_batch.bat

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
@echo off  
setlocal EnableDelayedExpansion

set MYPATH=%cd%
for /d %%a in (%MYPATH%\*) do (
echo %%a|findstr "pass" >nul
if not !errorlevel! equ 0 (
cd %%a
if exist %%a\.git\ (
echo %%a
git pull
echo ------------------------------------------------
) else (
for /d %%b in (%%a\*) do (
echo %%b|findstr "pass" >nul
if not !errorlevel! equ 0 (
cd %%b
if exist %%b\.git\ (
echo %%b
git pull
echo ------------------------------------------------
)
cd ..
)
)
)
cd ..
)

)
pause

这样把该文件放在项目文件夹下,双击运行即可。