学习这个古老的技能是因为最近 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 了解当前处于什么阶段。颜色
数值颜色数值颜色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--------
- %~t0 08/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 [path] %%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 :eof
复制代码 Windows 命令行长度有 8191 的限制,好在很多工具(gcc、cl、link)都支持将参数写到文件中,然后用 @%filename% 的方式读取。
Linux 命令行同样有长度限制,不过为 128K
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |