如何在Windows上的批处理文件中只设置一次PATH环境变量?

14 浏览
0 Comments

如何在Windows上的批处理文件中只设置一次PATH环境变量?

我有一个批处理文件,它会在Visual Studio IDE构建步骤中设置用户路径并运行。

@ECHO OFF
@ECHO %PATH%
set COMSPEC = "%VCINSTALLDIR%\vcvarsall.bat" amd64
setx PATH "..\..\lib\libsndfile;..\..\lib\simulink" 
@ECHO %PATH%

当我构建项目,关闭VS,重新打开并重新构建时,我会发现新的路径被追加到PATH变量中。然而,在Windows环境变量的设置中,PATH变量是在用户环境变量下创建的,内容为:

..\..\lib\libsndfile;..\..\lib\simulink

问题1:

为什么这个路径也会作为系统环境变量的一部分出现在追加的路径中?

在通过Visual Studio控制台执行echo %PATH%时(第二次运行项目时),打印出了系统变量路径以及我追加的新路径。

问题2:

我想修改我的批处理文件,使其在第一次运行Visual Studio构建时,只在用户设置中设置一次PATH环境变量。如果在后续运行中用户变量PATH已经存在,则不再执行set命令,以避免再次将新路径追加到系统变量中。

有什么好的解决方法吗?

0
0 Comments

编辑:经过一些测试,似乎我的原始答案并不完全适用于OP的问题。为了直接回答OP的问题:

1. %PATH%HKLM\System\CurrentControlSet\Control\Session Manager\Environment\Path的值与HKCU\Environment\Path的值结合。当你使用setx "dir;dir"时,你设置的是HKEY_CURRENT_USERPath值。机器范围的HKEY_LOCAL_MACHINEPath值保持不变。这就是为什么你看到的是追加值,而不是替换值的原因。你必须使用setx /m来替换HKLMPath值。但是,请不要这样做,除非你想在操作系统安装过程中创建严重的问题。

2.如果你想测试%PATH%中是否存在一个目录,你可以cdpushd到你想检查的目录和%PATH%中的每个目录,以统一每个目录,确保所有的相对路径、环境变量等都被展开。set "var=%CD%"然后对每个目录进行操作。if /I "!dir1!"=="!dir2!"目录已经在%PATH%中的某个地方存在。下面是我原来答案中的一个示例。

我的原始答案并不完全适用的原因是因为setx本身并不像我曾经想象的那样具有破坏性。危险在于,通常当用户想要将一个目录添加到他们的路径中时,他们会使用setx /m PATH "%PATH%;new dir";这是破坏性的。因为在setx写入值之前,%PATH%被展开,所有在PATH中的目录都被过早地展开。

下面是一个更安全的方法:

set "env=HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
for /f "tokens=2*" %%I in (
    'reg query "%env%" /v Path ^| findstr /i "\"'
) do setx /m PATH "%%J;new directory"

但这并不是OP问的,对于这个膝反应的答案我向你道歉。

原始答案:setx是具有破坏性的,不应该以这种方式使用。当你setx PATH时,你将注册表值的数据类型从REG_EXPAND_SZ转换为REG_SZ。一旦你这样做了,存储在%PATH%中的所有动态环境变量都会被转换为扁平的绝对路径。使用path命令将目录临时添加到你的%PATH%中,使用reg add永久添加。这里还有一个我写的工具脚本,以更安全的方式向我的%PATH%添加目录。它也会避免将同一个目录多次添加到%PATH%中,无论它的格式如何(例如,尾部反斜杠、相对路径、环境变量或任何其他排列组合)。

我用你给出的脚本调用了以上脚本中的一个路径。第一次,它显示了'Warning: %%PATH%% has changed. Reopen the console to inherit the changes'。下一次,使用相同的参数调用它不会显示"already exists in path"的消息,而是同一个路径被添加了两次。这在命令提示符和VS预构建事件调用中都发生了。

我突然想到,也许需要以提权方式运行脚本。你可以尝试以管理员身份运行它,看看是否有更好的运气?

嗨rojo。我将你的脚本添加到链接中,并确实打印出路径已添加的消息。但是,如果我进入注册表并查看添加的路径,我无法在"PATH"变量下找到它们的任何地方。实际上,我无法在任何地方找到这些路径。那么路径在哪里?其次,当我从VS IDE预构建事件中运行脚本时,使用call setdllpathSafe.bat "..\..\lib\libsndfile" & call setdllpathSafe.bat "..\..\lib\simulink",它在显示消息之前连续打印当前路径三次?

在Windows 7 SP1 x64上,使用setx和文件版本6.1.7600.16385,我再次尝试了一下我的批处理代码,并在批处理执行之前和之后查看了Path的注册表值类型。但是在每次修改后,注册表值类型都保持不变,即REG_EXPAND_SZ。我可以在Process Monitor中看到,setx首先查询Path,然后使用正确的类型进行设置。

相同的版本。转到HKLM\System\CurrentControlSet\Control\Session Manager\Environment并创建一个名为"foo"的新的REG_EXPAND_SZ值,将其数据设置为"bar"。保持该窗口打开,但打开一个控制台窗口,执行setx /m foo bar。现在返回到注册表编辑器窗口并刷新。"foo"现在是REG_SZ类型。但是我确实发现,如果我执行setx /m foo %bar%(其中%bar%未定义),setx将数据类型重新设置为REG_EXPAND_SZ。我忘记了我在哪里读到关于setx有破坏性的性质,但直到现在我才真正做了实验。

我想,我们只需要确保在使用setx添加目录时,%PATH%中的所有变量都保持折叠状态。

0
0 Comments

如何在Windows中的批处理文件中设置PATH环境变量?

问题出现的原因是,批处理中使用的Setx命令将路径添加到用户环境中,但%PATH%变量是根据系统环境和用户环境的路径来构建的。

解决方法是使用Setx命令将路径添加到用户环境中。如果路径已经存在于%PATH%中,则Setx不会重复添加。

有人问为什么重新定义系统变量%COMSPEC%。回答是为了在Visual Studio中成功进行后续路径添加。虽然回答2解决了问题,但出于好奇,是否有办法在下次运行批处理文件时从%PATH%中删除已添加的路径部分?

可以使用reg命令和wmic命令读取、编辑和写入想要的内容来实现。问题是Windows(也就是资源管理器)在注销/登录之前不知道路径已经改变。但是可以使用reg命令删除,并使用setx命令重新添加。Setx命令会向监视它的程序发送系统更改事件,资源管理器会重新构建路径,所以它启动的任何程序(如CMD)都会具有新的路径。

0