Bat&Powershell语法总结笔记
温馨提示:远离BAT语法,幸福你我他(ಡωಡ)
1   推荐链接
- 微软文档:代码页标识符(chcp)
- CMD命令例程索引:该网站的教程索引比微软官方文档好用。
2   检测并获取管理员权限
2.1   方式一:使用cacls工具检测权限
1 | @REM 检测权限:根据系统版本尝试访问系统文件路径 |
2.2   方式二:使用fsutil dirty query检测权限
1 | @echo off |
2.3   方式三:提权到System权限
1 | @REM 获取管理员权限 |
3   提权并传递参数
1 | @REM 提权之前先保存当前的命令行参数 |
4   打印输出
4.1   打印输出分割线
1 | :draw_line |
4.2   打印输出当前时间
1 | :log |
5   特殊字符
bat中有部分特殊字符,例如()<>&|
之类的,若需要输出打印特殊字符到终端控制台,则需要转义符号^
。如果传递变量值时需要转义的话,以&
符号为例,一般写法为^^^&
,^^
转义为^
,^&
转义为&
。
在本人代码实践中,如果使用使用双引号去设置变量的话,例如set "val=Mr. Kin ^^^<im.misterkin@gmail.com^^^>"
,传递过程中仍会出现解析异常,导致运行错误。如果不用双引号,直接使用单^
符号直接转义,例如set val=^<im.misterkin@gmail.com^>
则完全没问题。这点令人十分困扰。
6   字符串的处理
6.1   字符串的截取
%variable:~n,m%
- n:开始截取字符串的偏移量;如果为正数,则从左边开始;如果没有为负数,则从右边开始
- m:要截取字符的个数。如果没有指定个数,则采用默认值,即变量数值的余数(余数指剩余个数,如:%variable:~-5% 当前偏移量为倒数第6,将剩下的字符全部截取)。如果两个数字 (偏移量和长度) 都是负数,使用的数字则是字符串长度加上指定的偏移量或长度(参见实例2)。
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
28set ifo=abcdefghijklmnopqrstuvwxyz0123456789
echo 原字符串:
echo %ifo%
rem abcde
echo 截取前5个字符:
echo %ifo:~0,5%
rem fghijklmnopqrstuvwxyz0123456789
echo 截取第六个字符直到最后一个字符
echo %ifo:~5%
rem 56789
echo 截取最后5个字符:
echo %ifo:~-5%
echo %ifo:~-5,5%
rem abcdefghijklmnopqrstuvwxyz01234
echo 截取第一个到倒数第6个字符:
echo %ifo:~0,-5%
rem defgh
echo 从第4个字符开始,截取5个字符:
echo %ifo:~3,5%
rem wxyz0
echo 从倒数第14个字符开始,截取5个字符:
echo %ifo:~-14,5%
6.2   字符串的字符替换
BAT语法:%variable:str1=str2%
,缺陷:用以文本文件中整行处理中可能无法处理一些特殊字符,导致丢失某些内容。
1 | @REM 替换str中的xxx为yyy |
POWERSHELL语法:(Get-Content -Path '%file_path%') -replace '%search_string%', '%replace_string%' | Set-Content -Path '%file_path%'
,缺陷:用以文本文件中整行处理中可能无法处理一些特殊字符,导致丢失某些内容。不过比BAT语法使用起来更简单,而且无需特殊处理也能保留空格和换行符。推荐只修改特定字符串,%search_string%
无需填入过多的字符,例如将17改为20,只需搜索17字符串即可。
1 | powershell -Command "(Get-Content -Path '%file_path%') -replace '%search_string%', '%replace_string%' | Set-Content -Path '%file_path%'" |
6.3   去掉变量字符串中的空格
1 | set abc= aaabbbccc |
7   读取内容
“for /f
”常用来解析文本,读取字符串。
delims
参数负责切分字符串,指定分隔符。内容会根据实际分隔符分隔开。tokens
负责提取字符串,指提取的列数。例如tokens=12-4
,表示提取第1列,第2列至第4列的内容,有多少列就要有多少个输出变量,并且各变量中的字母存在先后顺序。第一个变量字母是自己定义的,推荐是使用%%a
,这样第二个列就是用%%b
来表示。m*
表示提取第m列和第m列之后的所有字符。
7.1   读取首行内容
1 | for /f "usebackq delims=" %%a in ("!drive!\!config_file!") do set "image_name=%%a" |
7.2   读取特定行数内容
1 | for /f "tokens=* delims=" %%i in ('diskpart /s auto_partition_opts ^| findstr /n "^" ^| findstr "^9:"') do set disk_model_name=%%i |
7.3   读取全部内容
FOR /F
默认是不会返回空行,因为该命令本身设计就是如此。
若想实现完全读取,可以使用findstr对文本内容先赋予一个行号,再逐行读取。
1 | ::preserve blank lines using FIND, assume no line starts with ] |
8   判断网络连通状态执行不同命令
1 | ping www.baidu.com -n 3 | findstr "TTL" >nul && goto network_well || goto network_bad |
9   将批处理运行结果显示并保存到文件
9.1   wtee方案
linux上有tee命令可以实现这个目的,wtee程序则是windows实现的tee版本。
9.2   临时文件中转方案
原理:使用call将想要输出结果输出到临时文件,之后进行:
- 先清屏,将临时文本内容显示,实现窗口显示的本次运行结果的功能。
- 将临时文本内容追加到日志文件用于保存。
- 删除临时文件。
1
2
3
4
5
6
7
8@echo off
call a.bat > log2.txt
cls
for /f "delims=" %%i in (log2.txt) do (
echo %%i
)
type log2.txt >> log.txt
del log2.txt
10   数组
创建数组:set a[0]=1
定义值列表并遍历值列表:
1 | @echo off |
遍历数组:
1 | @echo off |
计算数组长度:
1 | @echo off |
数组结构体:
1 | @echo off |
11   setlocal和endlocal的作用域
在setlocal和endlocal语句内的set变量,是属于局部变量。
如果用setlocal enabledelayedexpansion设置了延迟环境变量扩展,需要使用!variable!
来引用变量。
12   生成特定命令的批处理帮助文件
1 | @echo on |
13   字符集引起的“is not recognized as an internal or external command”
知识背景:系统终端默认的字符集是ANSI,但ANSI并非某一种特定的字符编码,在不同的系统中,ANSI表示不同的编码。比如原生英文系统的ANSI编码是ASCII编码,原生中文系统的ANSI编码是GBK编码。(code page实际是由系统的「区域和语言」控制的)
问题现象:当bat程序脚本文件本身用默认的utf-8编码保存,并且使用命令@chcp 65001>nul
切换代码页,仍然有概率执行是会导致echo
命令在输出中文出现解析错误,提示“is not recognized as an internal or external command”,比如使用注释命令@rem 中文注释
之后,再使用echo
打印输出中文时就出现解析错乱。
问题原因:具体引起的原因未知,目前猜测是当脚本程序执行不少命令之后,环境变量可能会出现错乱,导致部分命令解析失败。
解决方法有两种:
- 在
@rem 中文注释
命令之后重新执行@chcp 65001>nul
即可确保后面的命令正确解析执行。 - 将所有文件编码改为ANSI编码,比如简中系统,使用GBK编码。
14   在命令提示符中运行 PowerShell 命令
命令形式:powershell -command "xxx"
如果命令中有双引号,记得使用反斜杠转义双引号字符,避免最外层的双引号和里面的双引号一起被匹配解析。在PowerShell语法中,双引号 "" 视为文字字符串值的。因此需要确保符号被正确解析。
15   语法问题
15.1   ==
与equ
的对比区别
==
是用来比较相同的,即比较字符串是否完全相同的。EQU
是比较运算符,含有运算的功能,换句话说,是可以在比较之前转换数字为对应的数值,然后再比较。
数值是指十进制的数字,在前缀加 0×
(这里x忽略大小写)则表示十六进制数字,加 0
则表示八进制数字。因此,0x12
与 18
相同,也与 022
相同,八进制表示法容易引起混淆。例如,08
和 09
不是有效数字,因为 8
和 9
不是有效的八进制数字。
所以,在使用 ==
比较时,0x12
、022
和18
是不相等的,但在使用EQU
比较时,他们是相等的,因为他们对应的数值都是18
!
16   ps脚本无法运行
出于安全考虑,默认的 Windows PowerShell 策略不允许执行脚本。
设置运行策略:
1 | Get-ExecutionPolicy |
17   参考文献
[1] How to request Administrator access inside a batch file[EB/OL]. https://stackoverflow.com/questions/1894967/how‑to‑request‑administrator‑access‑inside‑a‑batch‑file.
[2] How to write a batch file can run parameters as command with administrative privi‑leges?[EB/OL]. https://stackoverflow.com/questions/38364617/how‑to‑write‑a‑batch‑file‑can‑run‑parameters‑as‑command‑with‑administrative‑priv.
[3] 批处理通过 ping 判断网络[EB/OL]. https://www.52pojie.cn/thread-1021861-1-1.html.
[4] 批处理 ping命令判断是否可以连接到一个网站[EB/OL]. https://lanlan2017.github.io/blog/318f3e6b/.
[5] Windows10一句话从administrator权限提升到system权限[EB/OL]. https://blog.csdn.net/mochu7777777/article/details/106842901.
[6] 在命令提示符中运行 PowerShell 命令[EB/OL]. https://www.delftstack.com/zh/howto/powershell/running-powershell-commands-in-cmd/.
[7] [系统相关] [已解决]批处理if中,== 与equ 这2个,在什么情况下会有区别?[EB/OL]. http://www.bathome.net/thread-15170-1-1.html.
[8] cmd 字符串替换[EB/OL]. https://blog.csdn.net/scimence/article/details/52816878.
[9] Bat 去掉变量字符串中的空格[EB/OL]. https://blog.csdn.net/a71468293a/article/details/127747191.
[10] 字符串截取操作[EB/OL]. https://www.hxstrive.com/subject/windows_bat/122.htm.
[11] 在使用bat 批处理 时将运行结果显示并保存到文件中 echo[EB/OL]. https://www.cnblogs.com/qiyuexin/p/11701362.html.
[12] for /f命令之—Delims和Tokens用法&总结[EB/OL]. https://blog.csdn.net/kagurawill/article/details/114982328.
[13] 批处理(bat)中的数组问题[EB/OL]. https://blog.csdn.net/qq_34414530/article/details/117839838.
[14] BAT批处理文件 setlocal,endlocal命令详解[EB/OL]. https://blog.csdn.net/csqxy547/article/details/89856034.
[15] [数值计算] [已解决]批处理()嵌套的变量延时与endlocal作用域问题[EB/OL]. http://www.bathome.net/thread-32880-1-1.html.
[16] How can I replace every occurrence of a String in a file with PowerShell?[EB/OL]. https://stackoverflow.com/questions/17144355/how-can-i-replace-every-occurrence-of-a-string-in-a-file-with-powershell.
[17] DOS batch FOR loop with FIND.exe is stripping out blank lines?[EB/OL]. https://stackoverflow.com/questions/8811992/dos-batch-for-loop-with-find-exe-is-stripping-out-blank-lines.
[18] Special Characters in Batch File[EB/OL]. https://stackoverflow.com/questions/37333620/special-characters-in-batch-file.