EnableDelayedExpansion 或调用集?
EnableDelayedExpansion or call set?
在这样的代码中:
set /p "PROGNAME=enter the name of the prog: "
set /p "VERSION=enter the version of the prog: "
setlocal enabledelayedexpansion
if "%PROGNAME%"=="foo" (
set "OPTIONS=(someParams)"
set "PROGPATH=C:\MyPath\%PROGNAME%%OPTIONS%_%VERSION%.exe"
) else if "%PROGNAME%"=="bar" (
set "OPTIONS=(otherParams)"
set "PROGPATH=C:\MyPath\%PROGNAME%%OPTIONS%_%VERSION%.exe"
)
set "PROGDLL=!PROGPATH:%PROGNAME%=%PROGNAME%dll!"
endlocal
我了解到 PROGPATH
变量需要 enabledelayedexpansion
,因为它与它需要的 OPTIONS
变量设置在同一个循环中,PROGDLL
变量,因为替换。
但是,在这种特殊情况下,我不希望变量是局部的。就像,一点也不;即使在脚本结束后我也想访问它们。所以enabledelayedexpansion
不能用
然后我做了这样的东西:
set /p "PROGNAME=enter the name of the prog: "
set /p "VERSION=enter the version of the prog: "
if "%PROGNAME%"=="foo" (
set "OPTIONS=(someParams)"
call set "PROGPATH=C:\MyPath\%PROGNAME%%OPTIONS%_%VERSION%.exe"
call set "PROGDLL=%%PROGPATH:foo=foodll%%"
) else if "%PROGNAME%"=="bar" (
set "OPTIONS=(otherParams)"
call set "PROGPATH=C:\MyPath\%PROGNAME%%%OPTIONS%%_%VERSION%.exe"
call set "PROGDLL=%%PROGPATH:bar=bardll%%"
)
虽然这很完美,但我现在很迷茫:如果它只需要 call set
,那么 enabledelayedexpansion
有什么意义??我的意思是,每次我需要在循环中设置一些因变量时,我一直在我的脚本中使用 enabledelayedexpansion
,我应该用 call set
替换所有这些变量并删除 enabledelayedexpansion
吗?
我想了解一般情况下什么时候应该使用 enabledelayedexpansion
什么时候应该使用 call set
。
(还有,为什么双 %%
和 call set
?)
好吧,您的代码实际上应该如下所示:
rem // At this point, the default state should apply, hence no delayed expansion:
set /P "PROGNAME=enter the name of the prog: "
set /P "VERSION=enter the version of the prog: "
setlocal EnableDelayedExpansion
rem /* At this point, delayed expansion should be applied for all possible variables,
rem because otherwise, you may run into problems with exclamation marks: */
if "!PROGNAME!"=="foo" (
set "OPTIONS=(someParams)"
rem /* You need `!OPTIONS!` here, of course, since it is set in the same block;
rem but you should also use `!PROGNAME!` and `!VERSION!` herein: */
set "PROGPATH=C:\MyPath\!PROGNAME!!OPTIONS!_!VERSION!.exe"
) else if "!PROGNAME!"=="bar" (
set "OPTIONS=(otherParams)"
set "PROGPATH=C:\MyPath\!PROGNAME!!OPTIONS!_!VERSION!.exe"
)
rem /* For the sub-string substitution, you should avoid immediate expansion,
rem because you may get in trouble with unbalanced quotes, if applicable;
rem you could use a `for /F` loop to delay expansion of search/replace strings;
rem as you can see, delayed expansion is used as much as possible, and
rem the whole replacement expression is transferred to the `for` meta-variable: */
for /F "delims=" %%S in ("!PROGNAME!=!PROGNAME!dll") do set "PROGDLL=!PROGPATH:%%I!"
rem /* To avoid loss of set variables due to end of the environment localisation,
rem use another `for /F` loop; delayed expansion is used as much as possible, and
rem the whole assignment expression is transferred to the `for` meta-variable: */
for /F "delims=" %%E in ("PROGPATH=!PROGPATH!") do endlocal & set "%%E"
请注意,设置变量仅在运行批处理脚本的同一 cmd.exe
实例中可用。
如果你想使用call
而不是延迟扩展,代码应该是这样的:
rem // At this point, the default state should apply, hence no delayed expansion:
set /P "PROGNAME=enter the name of the prog: "
set /P "VERSION=enter the version of the prog: "
setlocal EnableDelayedExpansion
if "%PROGNAME%"=="foo" (
set "OPTIONS=(someParams)"
rem // You need `call` here, of course, since `OPTIONS` is set in the same block:
call set "PROGPATH=C:\MyPath\%PROGNAME%%%OPTIONS%%_%VERSION%.exe"
rem /* Here is an alternative way using `%%` for all variables, which may avoid
rem problems with unbalanced quotes, but you may get unwanted `^`-doubling: */
rem call set "PROGPATH=C:\MyPath\%%PROGNAME%%%%OPTIONS%%_%%VERSION%%.exe"
) else if "!PROGNAME!"=="bar" (
set "OPTIONS=(otherParams)"
call set "PROGPATH=C:\MyPath\%PROGNAME%%%OPTIONS%%_%VERSION%.exe"
rem call set "PROGPATH=C:\MyPath\%%PROGNAME%%%%OPTIONS%%_%%VERSION%%.exe"
)
rem // Of course you will need `call` for the sub-string substitution:
call set "PROGDLL=%%PROGPATH:%PROGNAME%=%PROGNAME%dll%%"
但是请注意,这种方法速度较慢,并且您可能会遇到不必要的插入符号加倍问题 ^
。此外,%%
可能会导致 for
meta-variables 的意外扩展,例如,当代码放置在 %%P
适用的部分内时, call set "PROGDLL=<b>%%P</b>ROGPATH:…%%"
会导致意想不到的结果,因为 %%P
部分被扩展了。
在这样的代码中:
set /p "PROGNAME=enter the name of the prog: "
set /p "VERSION=enter the version of the prog: "
setlocal enabledelayedexpansion
if "%PROGNAME%"=="foo" (
set "OPTIONS=(someParams)"
set "PROGPATH=C:\MyPath\%PROGNAME%%OPTIONS%_%VERSION%.exe"
) else if "%PROGNAME%"=="bar" (
set "OPTIONS=(otherParams)"
set "PROGPATH=C:\MyPath\%PROGNAME%%OPTIONS%_%VERSION%.exe"
)
set "PROGDLL=!PROGPATH:%PROGNAME%=%PROGNAME%dll!"
endlocal
我了解到 PROGPATH
变量需要 enabledelayedexpansion
,因为它与它需要的 OPTIONS
变量设置在同一个循环中,PROGDLL
变量,因为替换。
但是,在这种特殊情况下,我不希望变量是局部的。就像,一点也不;即使在脚本结束后我也想访问它们。所以enabledelayedexpansion
不能用
然后我做了这样的东西:
set /p "PROGNAME=enter the name of the prog: "
set /p "VERSION=enter the version of the prog: "
if "%PROGNAME%"=="foo" (
set "OPTIONS=(someParams)"
call set "PROGPATH=C:\MyPath\%PROGNAME%%OPTIONS%_%VERSION%.exe"
call set "PROGDLL=%%PROGPATH:foo=foodll%%"
) else if "%PROGNAME%"=="bar" (
set "OPTIONS=(otherParams)"
call set "PROGPATH=C:\MyPath\%PROGNAME%%%OPTIONS%%_%VERSION%.exe"
call set "PROGDLL=%%PROGPATH:bar=bardll%%"
)
虽然这很完美,但我现在很迷茫:如果它只需要 call set
,那么 enabledelayedexpansion
有什么意义??我的意思是,每次我需要在循环中设置一些因变量时,我一直在我的脚本中使用 enabledelayedexpansion
,我应该用 call set
替换所有这些变量并删除 enabledelayedexpansion
吗?
我想了解一般情况下什么时候应该使用 enabledelayedexpansion
什么时候应该使用 call set
。
(还有,为什么双 %%
和 call set
?)
好吧,您的代码实际上应该如下所示:
rem // At this point, the default state should apply, hence no delayed expansion:
set /P "PROGNAME=enter the name of the prog: "
set /P "VERSION=enter the version of the prog: "
setlocal EnableDelayedExpansion
rem /* At this point, delayed expansion should be applied for all possible variables,
rem because otherwise, you may run into problems with exclamation marks: */
if "!PROGNAME!"=="foo" (
set "OPTIONS=(someParams)"
rem /* You need `!OPTIONS!` here, of course, since it is set in the same block;
rem but you should also use `!PROGNAME!` and `!VERSION!` herein: */
set "PROGPATH=C:\MyPath\!PROGNAME!!OPTIONS!_!VERSION!.exe"
) else if "!PROGNAME!"=="bar" (
set "OPTIONS=(otherParams)"
set "PROGPATH=C:\MyPath\!PROGNAME!!OPTIONS!_!VERSION!.exe"
)
rem /* For the sub-string substitution, you should avoid immediate expansion,
rem because you may get in trouble with unbalanced quotes, if applicable;
rem you could use a `for /F` loop to delay expansion of search/replace strings;
rem as you can see, delayed expansion is used as much as possible, and
rem the whole replacement expression is transferred to the `for` meta-variable: */
for /F "delims=" %%S in ("!PROGNAME!=!PROGNAME!dll") do set "PROGDLL=!PROGPATH:%%I!"
rem /* To avoid loss of set variables due to end of the environment localisation,
rem use another `for /F` loop; delayed expansion is used as much as possible, and
rem the whole assignment expression is transferred to the `for` meta-variable: */
for /F "delims=" %%E in ("PROGPATH=!PROGPATH!") do endlocal & set "%%E"
请注意,设置变量仅在运行批处理脚本的同一 cmd.exe
实例中可用。
如果你想使用call
而不是延迟扩展,代码应该是这样的:
rem // At this point, the default state should apply, hence no delayed expansion:
set /P "PROGNAME=enter the name of the prog: "
set /P "VERSION=enter the version of the prog: "
setlocal EnableDelayedExpansion
if "%PROGNAME%"=="foo" (
set "OPTIONS=(someParams)"
rem // You need `call` here, of course, since `OPTIONS` is set in the same block:
call set "PROGPATH=C:\MyPath\%PROGNAME%%%OPTIONS%%_%VERSION%.exe"
rem /* Here is an alternative way using `%%` for all variables, which may avoid
rem problems with unbalanced quotes, but you may get unwanted `^`-doubling: */
rem call set "PROGPATH=C:\MyPath\%%PROGNAME%%%%OPTIONS%%_%%VERSION%%.exe"
) else if "!PROGNAME!"=="bar" (
set "OPTIONS=(otherParams)"
call set "PROGPATH=C:\MyPath\%PROGNAME%%%OPTIONS%%_%VERSION%.exe"
rem call set "PROGPATH=C:\MyPath\%%PROGNAME%%%%OPTIONS%%_%%VERSION%%.exe"
)
rem // Of course you will need `call` for the sub-string substitution:
call set "PROGDLL=%%PROGPATH:%PROGNAME%=%PROGNAME%dll%%"
但是请注意,这种方法速度较慢,并且您可能会遇到不必要的插入符号加倍问题 ^
。此外,%%
可能会导致 for
meta-variables 的意外扩展,例如,当代码放置在 %%P
适用的部分内时, call set "PROGDLL=<b>%%P</b>ROGPATH:…%%"
会导致意想不到的结果,因为 %%P
部分被扩展了。