我无法使用^^!
转义感叹号。我知道我需要使用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
这是我的代码,没有错误,但是我不能正确地转义感叹号,结果是This is a test
而不是This is a test!
。 最佳答案
每次启用延迟扩展时,当文字字符串包含感叹号时,以及立即展开将感叹号保留在其字符串值中的变量(常规%
扩展)时,感叹号都会丢失(或导致其他意外结果)。 for
参数(例如%%I
)和参数引用(例如%1
)也是如此,因为所有这些参数都在延迟扩展发生之前被扩展了。
为避免任何此类问题,应仅在实际需要时才启用延迟扩展。
在您的代码中,您启用了全局延迟扩展。当您正确地将其转义时,变量Center
实际上会保存感叹号,但是一旦在%Center%
行中扩展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
除了纠正延迟扩展问题外,我还修复了以下问题:
exit
更改为exit /B
,以仅终止批处理脚本,而不终止父cmd
实例; echo.
更改为echo/
,因为如果当前目录中的文件名为echo
(无文件扩展名),则前者可能会失败; set
语法; %1
更改为%~1
,将%2
更改为%~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%% "
这说明了延迟扩展的一种替代方法:将变量周围的
%
符号加倍,并使用call
;但是,这并非在所有情况下都有效,因为某些字符可能仍然会引起麻烦,并且某些命令(例如for
和if
)无法由call
运行;