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 部分被扩展了。