是EnableDelayedExpansion还是呼叫集?

时间:2020-09-30 08:31:19

标签: batch-file set method-call

在这样的代码中:

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

我了解到enabledelayedexpansion变量都需要PROGPATH,因为它与变量OPTIONSPROGDLL处于同一循环中变量,因为替换。

但是,在这种特殊情况下,我不希望变量是局部的。就像,一点也不;即使在脚本结束后,我也想访问它们。因此无法使用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 setenabledelayedexpansion的意义是什么?我的意思是,每次需要在循环中设置一些因变量时,我都会在脚本中使用enabledelayedexpansion,是否应该将所有变量替换为call set并删除enabledelayedexpansion

一般来说,我想了解何时应该使用enabledelayedexpansion和何时应该使用call set

(还有为什么将%%call set一起使用?)

1 个答案:

答案 0 :(得分:1)

好吧,您的代码实际上应该像这样:

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元变量的意外扩展,例如,当代码放置在%%P适用的部分内时,call set "PROGDLL=%%PROGPATH:…%%"将导致因为%%P部分已扩展。