2016-10-16 39 views
4

嗨我是相当新的编码和我不能似乎能够逃脱使用^^!一个感叹号。我知道我需要使用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!

+2

你不需要'delayedexpansion' - 改变'''到'%'中:centertext'而失去了'endlocal' – Magoo

+0

@Magoo批处理文件当我改变不会跑'! '''%',它只是崩溃 – VanZuron

+0

@Magoo,由于嵌套扩展('!%1!'),实际上需要延迟扩展...... – aschipfl

回答

2

每次启用延迟扩展时,当文字字符串包含感叹号,并且当变量立即被扩展(正常%扩展)时,在其字符串中包含感叹号时,感叹号会丢失(或导致其他意外结果)值;对于for参数(例如,%%I)和参数引用(例如%1)也是如此,因为在延迟扩展发生之前所有这些参数都被扩展。
为避免此类问题,只有在实际需要时才能启用延迟扩展。

在您的代码中,您启用全局延迟扩展。变量Center实际上包含感叹号,因为您正确地转义它,但是只要在echo %spaces%%Center%行中扩展%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 

除了延迟扩展问题的修正,我也定了以下几件事:

  • 改变exitexit /B只终止批处理脚本,但不是父母cmd实例;
  • echo.更改为echo/,因为前者可能会失败,因为如果ther是当前目录中名为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;但这在所有情况下都不起作用,因为某些字符可能仍然会导致问题,并且某些命令(如forif)无法通过call运行;