如何将变量的值保留在使用“延迟扩展本地”模式的Windows批处理脚本之外?

时间:2012-08-18 16:16:08

标签: windows path batch-file environment-variables

上下文:我需要调用Windows批处理脚本,通过在其末尾添加另一条路径“PATH”来更新我的xxx,但是:

  • 没有任何重复
    (如果我将“xxx”添加到“aaa;xxx;bbb”之类的路径中,我需要更新的PATH,例如“aaa;bbb;xxx”)
  • 没有任何聚合
    (我可以反复调用脚本而不必使用“aaa;bbb;xxx;xxx;xxx;...”)

我尝试过:

以下功能负责处理任何重复并完成工作

:cleanAddPath -- remove %~1 from PATH, add it at the end of PATH
SETLOCAL ENABLEDELAYEDEXPANSION
set PATH=!PATH:%~2=!
set PATH=!PATH:;;=;!
set PATH=%PATH%;%~2
set P=!P:;;=;!
echo %PATH%
echo -------------
ENDLOCAL  
exit /b

但是,它需要delayed expansion local mode,这意味着:在脚本的末尾(或此处,在函数cleanAddPath的末尾),为{{1>设置的任何内容被扔掉

我可以要求用户(我为其编写脚本)使用%PATH%选项启动他们的cmd(激活延迟扩展,否则默认关闭),但这是不切实际的。

如何按照上述方式修改cmd /V:ON变量,并在调用该脚本后,在当前的DOS会话中更新它?

3 个答案:

答案 0 :(得分:6)

页面“DOS - Function Collection”提供了一个很好的示例,说明函数如何在DOS中返回值,即使使用delayed expansion模式:

以下函数将使用加法PATH更新所需的任何变量:

:cleanAddPath -- remove %~2 from %~1, add it at the end of %~1
SETLOCAL ENABLEDELAYEDEXPANSION
set P=!%~1!
set P=!P:%~2=!
set P=!P:;;=;!
set P=!P!;%~2
set P=!P:;;=;!
(ENDLOCAL & REM.-- RETURN VALUES
  SET "%~1=%P%"
)
exit /b

注意使用的路径串联。正如jeb comments

  

如果您的路径包含set P=%P%;%~2中的&符号,则行C:\Documents&Settings至关重要   更好地设置“P=!P!;%~2”。

SET "%~1=%P%"是允许记忆(在由%~1表示的变量中)使用延迟扩展功能设置的值的部分。
我最初使用SET "%~1=%P%" !,但jeb comments

  

命令SET "%~1=%P%" !可以简化为SET "%~1=%P%",因为尾随感叹号在延迟扩展模式下只有(良好)效果,如果您之前准备好了%P%

要更新PATH变量,您可以通过以下方式调用您的函数:

call :cleanAddPath PATH "C:\my\path\to\add"

在离开该脚本后,它会在你当前的DOS会话中持续存在。

dbenhamanswer指向一个更健全的答案(upvoted),但就我而言,这个脚本已经足够了。

答案 1 :(得分:3)

问题并不像你想象的那么简单。有许多问题可能会破坏您的代码,直到它需要在ENDLOCAL障碍中返回更新后的值。

我已经回答了这个问题,作为我为类似问题提供的答案的延伸。见How to check if directory exists in %PATH%?。在那个答案中,我提供了一系列使问题复杂化的问题 链接答案底部的代码显示了如果路径PATH中已经存在的话,如何可靠地添加路径,并且还演示了如何在ENDLOCAL障碍中可靠地返回值。

以下编辑来自VonC,试图在此处实际提供答案,而不仅仅是答案的链接。我将保留编辑功能,但如果没有完整链接答案的上下文,我会发现很难理解。

[答案演示了如何可靠地返回值]使用set "%~1=%var%" !技巧(尾随“!”)

该主题包括:

  
    

我不清楚。最后一个引号后面的感叹号如何影响变量内容?

  
     

延迟扩张的简单规则是:
  对于行中的每个字符,执行:

  • 如果是插入符号(^),则下一个字符没有特殊含义,删除插入符本身
  • 如果是感叹号,请搜索下一个感叹号(此处未观察到插入符号),然后展开到变量的内容
  • 如果在此阶段未找到感叹号,则会丢弃结果,而是使用之前阶段的结果(对于插入符很重要)
  

因此,此时差异应该是明确的,即使感叹号在一行中没有其他影响,也会删除插入符号。
  例如:

@echo off
setlocal EnableDelayedExpansion

echo one caret^^
echo none caret^^  !

set "var1=one caret^"
set "var2=none caret^" !

echo !var1!
echo !var2!
----- OUTPUT ----
one caret^
none caret
one caret^
one caret

答案 2 :(得分:2)

耶!最后使用以下测试代码:

@echo off
Setlocal enabledelayedexpansion

Set p="hello world"

( endlocal & rem return

   Set "a1=%p%"

)

Set a1

输出:

a1="hello world"

我在测试中使用延迟扩展而不使用任何!的原因是因为它仍会影响设置的工作方式,而我正在测试的批次都会延迟扩展。

感谢帮助人员:o)

PS我尝试为本地和外部环境使用相同的变量名,但这破坏了代码。因此使用了2个名字。