Van*_*ron 5 escaping batch-file
我无法逃避使用感叹号^^!。我知道我需要使用setlocal disabledelayedexpansion或只是使用,endlocal但我找不到合适的位置来放置它而不会出现任何错误。
这是我的脚本,旨在在cmd窗口的水平中心显示文本:
@echo off
setlocal enabledelayedexpansion
title Center Text
mode 80,50
set "cmdwidth=80"
:Display
cls
set Center=This is a test^^! & call :CenterText Center strLen
echo.
pause
exit
:CenterText
if not "!%1:~%len%!"=="" set /A len+=1 & goto :CenterText
(endlocal & set %2=%len%)
goto CenterTextDisplay
:AddSpace
set "spaces=%spaces% "
goto :eof
:CenterTextDisplay
set /a "indent=(cmdwidth - strLen)/2"
set "spaces= "
for /l %%a in (1,1,%indent%) do call :AddSpace
echo %spaces%%Center%
set "len=0"
goto :eof
Run Code Online (Sandbox Code Playgroud)
这是我的代码,没有错误,但我无法正确转义感叹号,结果This is a test不是This is a test!.
每次启用延迟扩展时、当文字字符串包含感叹号时以及当%在其字符串值中包含感叹号的变量立即扩展(正常扩展)时,感叹号都会丢失(或导致其他意外结果);for对于参数(例如,%%I)和参数引用(例如, )也是如此%1,因为所有这些都在延迟扩展发生之前扩展。
为了避免任何此类问题,延迟扩展应仅在实际需要时启用。
在您的代码中,您可以全局启用延迟扩展。当您正确转义该变量Center时,该变量实际上保留了感叹号,但一旦%Center%在 line 中扩展,它就会丢失echo %spaces%%Center%。
这是改编后的脚本:
@echo off
setlocal DisableDelayedExpansion
title Center Text
mode 80,50
set "cmdwidth=80"
:Display
cls
set "Center=This is a test!" & call :CenterText Center strLen
echo/
pause
endlocal
exit /B
:CenterText
setlocal EnableDelayedExpansion
:CenterText_Loop
if not "!%~1:~%len%!"=="" set /A len+=1 & goto :CenterText_Loop
endlocal & set "%~2=%len%"
set /a "indent=(cmdwidth-strLen)/2"
set "spaces= "
for /l %%a in (1,1,%indent%) do call :AddSpace
echo(%spaces%%Center%
set "len=0"
goto :eof
:AddSpace
set "spaces=%spaces% "
goto :eof
Run Code Online (Sandbox Code Playgroud)
除了修复延迟扩展问题外,我还修复了以下问题:
exit为exit /B仅终止批处理脚本而不终止父cmd实例;echo.,echo/因为如果echo当前目录中有名为(无文件扩展名)的文件,则前者可能会失败;set通过一致地引用整个赋值表达式来改进语法;%1为%~1和%2to%~2以从扩展值中删除潜在的引号;将子程序:AddSpace向下移动以澄清执行流程并避免需要标签:CenterTextDisplay和相关内容goto;
实际上,如果将命令行替换for /l %%a in (1,1,%indent%) do call :AddSpace为以下内容,您甚至可以删除该子例程:
for /l %%a in (1,1,%indent%) do call set "spaces=%%spaces%% "
Run Code Online (Sandbox Code Playgroud)
这说明了延迟扩展的另一种选择:将%变量周围的符号加倍并使用call; 但这并不适用于所有情况,因为某些字符仍然可能会引起麻烦,并且某些命令(如for和if)无法通过call;运行。