Windows批处理如何无需手动转义特殊字符定义复杂字面字符串
编写批处理文件通过azcopy将文件复制到Azure Storage Explorer时,希望可以直接将SAS密钥复制粘贴到批处理文件中,无需每次手动查找转义&、=这类特殊字符。
如何在批处理文件中便捷定义包含特殊字符的复杂字符串,让内容不被解析,也不需要手动转义?是否存在可用于set语句的关键字,实现「变量值中所有字符按原样使用,不做任何解析」的效果?已知部分编程语言用双引号包裹即可实现字面量定义,不清楚批处理中如何实现同等效果。
测试用伪SAS密钥:nifty-11-stuff%3A28GOOBER%3A5&se=2022
需求为将该字符串完整原样存入变量,保证后续批处理命令调用时值完全不发生变化。
初始测试代码:
@echo off setlocal EnableDelayedExpansion set SAS="nifty-11-stuff%3A28GOOBER%3A5&se=2022" echo %SAS% pause
实际运行输出:
"nifty-11-stuffA28GOOBERA5&se=2022"
错误原因:批处理对
%的解析优先级最高,双引号无法屏蔽%的解析逻辑,脚本会把%3识别为批处理的第3个位置入参,无入参时该位置会被替换为空值,最终输出错误内容;同时原写法把双引号写在了值的范围内,引号本身也会被存入变量,后续拼接azcopy命令时会出现格式错误。
批处理没有原生的「整段字符串完全不解析」的关键字,但可以通过两种方案实现接近零修改粘贴SAS密钥的效果:
方案1:完全无需转义,直接粘贴密钥(推荐)
利用批处理读取自身文件标签内容时不会触发特殊字符解析的特性,只需要把SAS密钥直接粘贴到指定标签行即可,不需要修改任何字符:
@echo off setlocal DisableDelayedExpansion for /f "usebackq delims=" %%i in (`findstr /b "::SAS_KEY:" "%~f0"`) do set "SAS=%%i" set "SAS=%SAS:~9%" setlocal EnableDelayedExpansion :: 后续azcopy命令调用SAS变量时,统一用!SAS!格式,不要用%SAS% echo 读取到的SAS值:!SAS! pause goto :eof :: 下方直接粘贴你的SAS密钥,保留::SAS_KEY:前缀即可,不需要修改密钥里的任何字符 ::SAS_KEY:nifty-11-stuff%3A28GOOBER%3A5&se=2022
实现逻辑:
- 初始关闭延迟扩展,避免密钥中存在
!字符时被解析丢失 - 通过findstr从当前批处理文件自身读取以固定前缀开头的行,读取全程不会触发
%、&、=等特殊字符的解析 - 截掉行开头的9位固定前缀后,剩余内容就是完全原始的密钥值,没有任何字符变动
- 开启延迟扩展后用
!SAS!格式调用变量,避免调用时触发二次解析
方案2:仅转义%字符的轻量方案
如果不想用自读取标签的写法,记住批处理中双引号可以屏蔽&、=、|、<、>这类特殊字符,唯独无法屏蔽%,只需要把密钥里所有单个%替换为两个%即可,其他字符完全不用修改,注意set语句要把引号写在等号外侧,避免引号被存入变量:
@echo off setlocal DisableDelayedExpansion :: 仅将原密钥中的%替换为%%,&、=等字符无需改动 set "SAS=nifty-11-stuff%%3A28GOOBER%%3A5&se=2022" setlocal EnableDelayedExpansion echo 读取到的SAS值:!SAS! :: 后续调用同样使用!SAS!格式 pause
注意事项:
set "变量名=值"是批处理定义变量的标准写法,外层引号不会被存入变量值,同时可以屏蔽值内特殊符号的解析- 禁止写成
set 变量名="值"的格式,这种写法会把前后双引号作为变量值的一部分存储,后续拼接URL时会出现格式错误 - 调用包含特殊字符的变量时,必须用延迟扩展的
!包裹,不要用%包裹,否则值内的特殊字符还是会被二次解析。
内容的提问来源于stack exchange,提问作者Jared

