频鹏凶 发表于 13 小时前

Windows bat 脚本学习记录

学习这个古老的技能是因为最近 2024.8.28 优化 Windows build 脚本遇到了一些不懂的内容,故而想要系统的进行学习并记录(权当技术沉淀)
参考文献:《Windows 命令行详解手册》第二版第三章
由于 Windows 命令不区分大小写,故而可能出现大小写混用问题。另外命令行有些操作较为反常识,使用时还是多借助 AI 和小测例搞清楚。
回显

windows bat 脚本本质上就是一行行的在控制台上输入命令,导致此执行脚本的时候就会有一长串的输出,干扰了我们观察结果。所以通常 bat 脚本的第一行有 @echo off 来关闭回显。
这里在行首加上 @ 表示关闭此行的回显。@echo off 的意思是关闭后续回显,此行的回显也不出现。
当脚本运行出现问题时,echo on 或删掉/注释掉第一行,根据回显的输出诊断脚本出错位置。
特殊用法

:: 查看 echo 状态是开启还是关闭
echo
:: 显示空行
echo .注释


[*]如果这行注释是提示信息,我们可以使用 rem 进行注释(在 echo on 时会回显)
[*]如果这行注释只是解释脚本的功能、创建时间、作者信息等可以用 @REM 或 :: 进行注释(始终不回显)
标题

TITLE 命令即可,在执行长耗时的任务时,通过切换 TITLE 了解当前处于什么阶段。
TITLE 学习 Windows Shell 中颜色

数值颜色数值颜色0黑8灰1蓝9淡蓝2绿A淡绿3浅绿B浅水绿4红C浅红5紫D淡紫6黄E淡黄7白F亮白color [背景颜色数值][文字颜色数值]例如 color 21 表示绿色背景蓝色文字。默认是黑背景白字即 color 07。注意这两个数值不能一致,否则设置不生效(合理)。
变量

有些变量(包括系统和用户环境变量)在 Shell 中有特殊用途,例如 path、computername、homedrive。另外还有 errorlevel, 一个用于跟踪最近使用命令的退出代码。

[*]返回 0 表示正常执行
[*]返回 1 表示通常错误
[*]返回 2 表示执行错误:命令没有正确执行
[*]返回 -2 代表算术错误:创建命令 shell 无法处理的过大的数
当然了用户脚本可以随意指定错误码,只要保证 0 是正常执行即可
定义变量

set variable_name=variable_value注意在变量名与变量值中,空格都是有效的!因此按照
:: 将变量 a 值置为空,也是声明变量的方式
set a=

:: 定义的变量是 `x `, 请尽量避免这样的写法!
set x = 123
:: 输出变量
echo %x %上述 echo %x输出内容为123。
注意 shell 中所有变量都是以字符串的形式存储,即使将变量的值设置为数值也是如此!另外 @, , &, |, ^ 为命令行保留字符(应该尽量避免出现在变量或者值中)。
echo 2^&3 输出内容为 2&3,echo 2^^3 输出内容为 2^3,但如果要定义变量,需要处理为
set x=2^^^&3
set y=2^^^^3
echo %x%
echo %y%变量范围局部性

shell 中定义的变量仅在当前 shell 以及当前 shell 启动的 shell 中有效(嵌套命令的 shell),如果想让变量仅在一个小区域可见,可以用 setlocal 和 endlocal 包起来
setlocal
set x=1
echo %x%
endlocal
echo %x%变量替换

set X="C:\Users\czp\cuzperf\cplib"
set X=%X:\=/%
echo %X%把 \ 替换成 /
参数


[*]%0 脚本名
[*]%1 - %9 第 1 到 9 个参数
[*]%* 所有参数
[*]shift 把所有参数左移, %0 被丢弃, 原 %1 变成 %0,以此类推
[*]shift /n, 原 %(n+1) 变成 %n, 以此类推
[*]%~1 ,以此类推
变形


[*]%~a 表示去掉第 %a 中的引号(如果有的话)
[*]%~dpa 表示 %a 所在的绝对路径
[*]%~da 表示 %a 所在路径所在的盘
[*]%~pa 表示 %a 所在绝对路径(不包括盘)
[*]%~na 表示 %a 文件名(不带后缀)
[*]%~xa 表示 %a 文件后缀
这些变形可以组合使用例如 %~dpa
从而可以推出

[*]%~0 去掉脚本中的引号
[*]%~dp0 为当前脚本所在的绝对路径
[*]%~d0 当前路径所在的盘
[*]%~p0 当前路径所在绝对路径(不包括盘)
[*]%~n0 脚本名去掉后缀
[*]%~x0 脚本后缀
[*]%~nx0 脚本名
例如运行 "C:\Users\czp\Documents\WeChat Files\test.bat" 则
%0      "C:\Users\czp\Documents\WeChat Files\test.bat"
%~0   C:\Users\czp\Documents\WeChat Files\test.bat
%~f0    C:\Users\czp\Documents\WeChat Files\test.bat
%~dp0   C:\Users\czp\Documents\WeChat Files\
%~d0    C:
%~p0    \Users\czp\Documents\WeChat Files\
%~n0    test
%~x0    .bat
%~s0    C:\Users\czp\DOCUME~1\WECHAT~1\test.bat
%~a0    --a--------
%~t008/29/2024 15:09数学表达式

使用 set /a,所有数学表达式都是针对 32 位有符号整数进行运算,取值范围为 \([-2^{31}, 2^{31} - 1]\),否则 errorlevel 非零
set /a 1 + 2
set /a x= 1 + 2
echo %x%比较运算符

==, equ, neq, lss, leq, gtr, geq
比较时默认是大小写敏感的,加上 /I 或 /i 则大小写不敏感
for 循环

for 循环有多重形式,最基本的为 for iterator do (statement) 的句型

[*]iterator 变量只出现在 for 循环中
[*]变量名必须在 a~z 或 A~Z 范围内, 例如 %%A, %%b
在命令行交互模式下 %%A 应该写成 %A
for 遍历值

for /l %%a in (0, 2, 10) do (
echo %%a
)输出为 0, 2, 4, 6, 8, 10(每个数字都换行)
for 遍历文件

for %%a in (./*.txt ./*.md) do (
echo %%a
)示例遍历当前路径下所有 txt 和 md 文件
for 遍历目录

for /d %%a in (%SystemRoot%\*) do (
echo %%a
)列出 %SystemRoot% 下所有目录,但不嵌套,想要嵌套可以再添加 /r 选项,但语法稍有不同: for /r %%variable in (fileSet) do (statement)
例如
for /r %SystemRoot% %%a in (*.txt) do (
echo %%a
)for 循环分析文件的内容与输出

for /f ["options"] %%variable in (source) do (statement)

[*]usebackq 可以用来处理名字中有空格,变量值用引号包起来的情况(十分有用!)
[*]tokens 挺有趣但可不用
[*]delims 指定分隔符
创建子程序与过程

:: 用 : 定义 lable,然后就可以 goto 了
:lable:subfunc
:: do something

:: 返回到调用的地方
goto :eof注意事项

对于复杂场景,应尽量使用延迟拓展功能:
setlocal enableDelayedExpansion
set LAST_PARAM=""
call :deal_params -I
call :deal_params "C:/24b(daynew)/Hello World"
:deal_params
if %LAST_PARAM% == "" (
set LAST_PARAM="%~1"
goto :eof
)
set "CUR_PARAM=%~1"
if %LAST_PARAM% == "-I" (
echo /I %1 >> 1.txt
echo !CUR_PARAM! >> 2.txt
)
set LAST_PARAM=""
goto :eof如果不使用延迟拓展功能,则会出现莫名其妙的报错
set LAST_PARAM=""
call :deal_params -I
call :deal_params "C:/24b(daynew)/Hello World"
:deal_params
if %LAST_PARAM% == "" (
set LAST_PARAM="%~1"
goto :eof
)
if %LAST_PARAM% == "-I" (
echo /I %1 >> 1.txt
echo %~1 >> 2.txt
)
set LAST_PARAM=""
goto :eofWindows 命令行长度有 8191 的限制,好在很多工具(gcc、cl、link)都支持将参数写到文件中,然后用 @%filename% 的方式读取。
Linux 命令行同样有长度限制,不过为 128K

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Windows bat 脚本学习记录