在cmd.exe中,如何让一个变量不受setlocal命令影响?

10

cmd.exe中,我经常使用setlocal命令来避免使用临时变量污染环境变量空间(同时确保启用了命令扩展和延迟环境变量扩展)。

但是,如果我想要其中一个变量可供使用,我该怎么做呢?

请考虑以下代码,它可以获取当前目录的最后一个组成部分(例如对于路径c:\pax\dir1,将返回dir1):

        @echo off
    :main
        setlocal enableextensions enabledelayedexpansion
        call :func
        echo.main_folder = %folder%
        endlocal
        goto :eof
:func setlocal enableextensions enabledelayedexpansion set temp=%cd% set folder= :funcloop1 if not "x%temp:~-1%"=="x\" ( set folder=!temp:~-1!!folder! set temp=!temp:~1,-1! goto :funcloop1 ) echo.func_folder = %folder% endlocal goto :eof

当我运行这段代码时,输出为:

func_folder = dir1
main_folder =
您可以发现,%folder% 变量在 endlocal 后没有被保留。但是,如果我在函数中去掉 setlocal/endlocaltemp 变量将污染 main 的命名空间。
我知道我可以在 func 结尾处使用 set temp= 来移除环境变量,但这并不适用于已经在外部作用域中使用该变量的情况(在这种情况下,它会完全被销毁)。
cmd.exe 中是否有一种方法允许选择性的环境变量传播到外部作用域,同时防止其他变量影响它?换句话说,您是否可以同时拥有局部变量和返回变量?
此外,请不要告诉我有更好的方法来获取最终路径组件。那只是一个示例而已。
实际上,您可以告诉我有更好的方法,因为了解这些方法很好,但这不会回答我的具体问题 :-)
3个回答

12
"The solution to this is to take advantage of the fact that the CMD shell evaluates variables on a line-by-line basis - so placing ENDLOCAL on the same line as the SET statement(s) gives the result we want:" source: ss64.com So changing the endlocal of func: to this...
endlocal & set folder=%folder%

...这将会让你获得你想要的行为。


加上一些括号? - Ben Voigt
不据我所知,这个“&”符号作为分隔符而非运算符。当然,使用括号也不会有害,如果您愿意可以自由使用。 - Robert Groves
太棒了。完美运行,包括多个 && set 命令以允许超过一个变量逃逸。 - paxdiablo
抱歉,我想说的是引号,而不是括号。 - Ben Voigt

3
为了更好的阅读和格式化,您可以使用括号。
call :func resultVar
echo(%resultVar%
goto :eof

:func 
setlocal
set var=2
(
  endlocal
  if "%1" NEQ "" set "%1=%var%"
  goto :eof
)

这个方法可行,因为命令块会像单行一样扩展。 在执行命令块之前,解析器会先扩展前两个阶段(百分号变量和转义字符)。 其他阶段会按时间顺序执行(例如延迟扩展、通过CALL进行第二次扩展等)。


0

endlocal && set aaa=%aaa% && set bbb=%bbb%会永久地设置setlocal之外的aaabbb,并在命令提示符中保留此设置供另一个批处理文件使用(例如,如果包含setlocal的批处理文件是从另一个批处理文件中调用的,则调用批处理文件现在将具有aaabbb的新设置)。

感谢向我解释endlocal && set的人。我查阅了无数网站以获得这个简单情况的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接