如何保持使用“延迟扩展本地”模式的Windows批处理脚本以外的variables值?

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

  • 没有任何重复
    (如果我添加“ xxx ”到像“ aaa;xxx;bbb ”这样的PATH ,我需要一个更新的PATH如“ aaa;bbb;xxx ”)
  • 没有任何聚集
    (我可以反复地调用脚本而不会以' aaa;bbb;xxx;xxx;xxx;... '结尾)

我曾经尝试过:

下面的function负责任何重复和做这项工作

 :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 

但是,它需要延迟扩展本地模式 ,这意味着:在脚本的末尾(或者在函数cleanAddPath ), 已经为%PATH%设置的任何东西都被抛弃了

我可以让用户(我为其编写脚本)使用cmd /V:ON选项启动他们的cmd (激活延迟的扩展,否则默认closures),但这是不实际的。

我怎样才能修改PATHvariables我上面描述的方式,并仍然有它调用上述脚本后,在我当前的DOS会话更新?

页面“ DOS – 函数集合 ”给出了一个很好的例子,即使在使用延迟扩展模式时,函数如何在DOS下返回一个值:

下面的函数将用一个加法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 评论 :

如果你的路径包含&符号,就像C:\Documents&Settings那样, set P=%P%;%~2是非常重要的。
更好地设置“ P=!P!;%~2 ”。

SET "%~1=%P%"是允许使用延迟扩展特征记忆的部分(在由%~1表示的变量中)。
我最初使用SET "%~1=%P%" ! ,但jeb 评论 :

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

要更新您的PATH变量,您可以使用以下函数调用您的函数:

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

并且在离开该脚本之后,对于当前的DOS会话,它将一直存在。

dbenham的答案指向一个更强大的答案(upvoted),但在我的情况下,这个脚本就足够了。

问题不像你想的那么简单。 有很多问题可能在代码到达需要在ENDLOCAL屏障上返回更新值的末端之前破坏您的代码。

我已经回答了这个问题,作为我为类似问题提供答案的延伸。 请参阅如何检查%PATH%中是否存在目录? 在这个答案中,我提供了一大堆使问题复杂化的问题。
链接答案底部的代码展示了如何可靠地添加路径(如果路径中不存在PATH ,还演示了如何可靠地将值返回ENDLOCAL屏障。

下面的编辑来自VonC,试图把答案放在这里,而不仅仅是一个答案的链接。 我将保留编辑,但是如果没有完整链接的答案,我会发现很难跟上。

[答案演示了如何使用set "%~1=%var%" !可靠地返回值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 

好极了! 最后得到这个工作与以下测试代码:

 @echo off Setlocal enabledelayedexpansion Set p="hello world" ( endlocal & rem return Set "a1=%p%" ) Set a1 

这输出:

 a1="hello world" 

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

感谢帮助家伙:o)

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