有人可以给我一个例子,说明批处理脚本在有或没有延迟扩展的情况下会有不同的行为吗? 是否存在您不想使用延迟扩展的情况?谢谢。
看下面的例子...
示例1:以下代码没有使用延迟扩展,因此for循环中的变量仅扩展一次。这意味着,无论我们使用 set 命令对其执行什么操作,在循环的每次迭代中,
%Count%
始终会扩展为 0
:
@echo off
set COUNT=0
for %%v in (1 2 3 4) do (
set /A COUNT=%COUNT% + 1
echo Count = %COUNT%
)
pause
所以这个脚本将输出:
Count = 0
Count = 0
Count = 0
Count = 0
这不是这个循环应该如何工作的。
示例 2: 另一方面,如果我们使用延迟扩展,我们有以下脚本,它将按预期运行。
setlocal ENABLEDELAYEDEXPANSION
set COUNT=0
for %%v in (1 2 3 4) do (
set /A COUNT=!COUNT! + 1
echo Count = !COUNT!
)
pause
并且,正如预期的那样,它将输出:
Count = 1
Count = 2
Count = 3
Count = 4
当您使用
ENABLEDELAYEDEXPANSION
并使用 !
而不是 %
扩展变量时,该变量每次都会重新扩展,并且一切都会按预期进行。
我想添加一个很好的示例,说明“EnableDelayedExpansion”(EDE)如何在无处不在的 FOR 循环示例之外发挥作用。
这是我想要解析的一行地震数据(我将其称为1line.txt)
ak_11574812 2015.04.29.193822 62.9525 -148.8849 1.0 9.5 1 阿拉斯加州坎特韦尔以南 49 公里
我遇到的问题是该行的最后一段并不总是从相同的列号开始。因此,我需要创建一个灵活的 SET 命令来准确地拔出该行的最后一段。
ECHO OFF
setlocal enableDelayedExpansion
set where=72
set /p line=<1line.txt
set locate=!line:~%where%,28!
echo %locate%
EDE 允许我将一个变量(其中)放置在另一个变量(行)内。 EDE 将首先翻译 % 括起来的变量,然后处理 ! 括起来的变量。并(在本例中)将结果推送到“locate”变量中。
Max 的回答给出了一个示例,说明批处理脚本在有或没有延迟扩展的情况下会有不同的行为。
为了完整起见,让我们回答问题的另一部分并展示当数据包含感叹号!
时您不想使用延迟扩展的情况(并展示处理此类数据的两种方法):
@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "_auxFile=%temp%\%~n0.txt"
rem create multiline sample file
>"%_auxFile%" ( for /L %%G in (1,1,3) do echo line %%G is 100%% valid! Sure! Hurrah!)
rem create one-line sample file
>"%_auxFile%" echo this line is 100%% valid! Sure! Hurrah!
echo(
echo --- file content
type "%_auxFile%"
echo(
SETLOCAL EnableDelayedExpansion
echo --- enabled delayed expansion chokes down unescaped exclamation marks^^^! "^!"
for /F "usebackq delims=" %%G in ("%_auxFile%") do (
set "_auxLine=%%~G"
echo loop var=%%~G
echo _auxLine=!_auxLine!
)
ENDLOCAL
echo(
SETLOCAL DisableDelayedExpansion
echo --- toggled delayed expansion works although might be laborious!
for /F "usebackq delims=" %%G in ("%_auxFile%") do (
set "_auxLine=%%G"
echo loop var=%%G
SETLOCAL EnableDelayedExpansion
echo _auxLine=!_auxLine!
ENDLOCAL
)
ENDLOCAL
echo(
SETLOCAL DisableDelayedExpansion
echo --- keep delayed expansion DISABLED: use CALL command!
for /F "usebackq delims=" %%G in ("%_auxFile%") do (
set "_auxLine=%%G"
echo loop var=%%G
call :ProcessVar
)
ENDLOCAL
rem delete the sample file
del "%_auxFile%"
ENDLOCAL
goto :eof
:ProcessVar
echo _auxLine=%_auxLine%
echo WARNING: neither !_auxLine! nor %%G loop variable is available here!
goto :eof
请注意,上面的脚本显示了正确的转义方法
%
百分号由%%
加倍(延迟扩展无关紧要),并且!
感叹号:
"^!"
如果用一对双引号括起来,则使用 cmd
和批处理脚本通用转义字符 ^
脱字符号;^^^!
否则,请使用三个 ^
插入符。输出:
==> D:\bat\SO\10558316.bat
--- file content
this line is 100% valid! Sure! Hurrah!
--- enabled delayed expansion chokes down unescaped exclamation marks! "!"
loop var=this line is 100% valid Hurrah
_auxLine=this line is 100% valid Hurrah
--- toggled delayed expansion works although might be laborious!
loop var=this line is 100% valid! Sure! Hurrah!
_auxLine=this line is 100% valid! Sure! Hurrah!
--- keep delayed expansion DISABLED: use CALL command!
loop var=this line is 100% valid! Sure! Hurrah!
_auxLine=this line is 100% valid! Sure! Hurrah!
WARNING: !_auxLine! as well as %G loop variables are not available here!
==>
正如答案中所指出的,延迟扩展的主要用途是在括号上下文中设置和访问变量。
尽管它在其他情况下也很有用。
@echo off
setlocal enableDelayedExpansion
set "string=test string value"
set start=5
set get_next=6
echo #!string:~%start%,%get_next%!#
set "search_for=string"
set "replace_with=text"
echo #!string:%search_for%=%replace_with%!#
输出将是:
#string#
#test text value#
虽然这可以通过额外的调用来实现,但这种方式的性能更高
@echo off
echo first attempt:
(
echo "%~1"
shift
echo "%~1"
)
::now the shift command will take effect
setlocal enableDelayedExpansion
echo second attempt:
(
set /a argument=1
call echo %%!argument!
shift
call echo %%!argument!
)
输出将是:
first attempt:
"first argument"
"first argument"
second attempt:
"second argument"
"third argument"
如您所见,参数化参数访问只能通过延迟扩展来完成。
另一种混合
!
和 %
的方法,这对于嵌套循环可能很有用:
@echo off
setlocal enabledelayedexpansion
set begin=2
set end=2
set string=12345
for /f "tokens=1,2" %%A in ("!begin! !end!") do set "string2=!string:~%%A,%%B!"
echo !string2!
endlocal
正如您现在所看到的,for 命令标记用作参数。
这里的几个答案回答了“如何使用延迟扩展?”问题或者如果不使用延迟扩展会发生什么。然而,第二个问题是“是否有任何情况下您不想使用延迟扩展?”有几个答案将这个问题视为“如何避免使用延迟扩展带来的问题?”
我的回答回答了我所理解的问题:“在哪些情况下最好不要使用延迟扩展(而不是使用它)?”
如果要交换两个变量的内容,执行此操作的最简单方法是使用 %standard% 变量扩展:
set "var1=%var2%" & set "var2=%var1%"
%standard% 扩展的工作方式使得无需使用任何辅助变量即可实现此替换。据我所知,批处理文件“编程语言”是唯一允许以这种方式执行这种交换的语言,即充分利用语言“功能”(而不是通过专门的“交换”指令/声明)。
这是一个让我大吃一惊的例子
set A=)\
echo %A%
(echo %A%)
第一个
echo
按预期工作,但第二个 echo
爆炸了。这些不一定是独立的括号,它们可以是 if
或 for
语句的一部分,没关系。
C:\>set A=)\
C:\>echo )\
)\
\) was unexpected at this time.
C:\>(echo )\)
解释是变量扩展发生在之前语法评估。