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

时间:2015-08-07 20:12:47

标签: batch-file

我有批处理文件,用于设置用户路径,并作为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 命令以避免在系统变量中反复添加新路径。

任何想法如何实现这一目标?

2 个答案:

答案 0 :(得分:6)

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

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

  2. 如果您想测试%PATH%中是否存在目录,您可以cdpushd同时查看要检查的目录以及%PATH%内的每个目录1}}统一每个,确保所有相对路径,环境变量等都是平坦的。每个set "var=%CD%"。然后if /I "!dir1!"=="!dir2!"目录已存在于%PATH%中的某个位置。我的原始答案中有一个例子。

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

    以下方法会更安全:

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

    但这并不是OP所要求的,我为这个下意识的回答道歉。

    原始回答: setx具有破坏性,不应以这种方式使用。当您setx PATH时,您将注册表值数据类型从REG_EXPAND_SZ转换为REG_SZ。一旦执行此操作,存储在%PATH%中的所有动态环境变量都将转换为平坦的绝对路径。使用path命令暂时将目录附加到%PATH%,并reg add永久附加目录。 (另请注意,还有dpath,它会临时在您的路径中添加一个目录,但只能由type命令使用。向下滚动2/3向下this page有关dpath的更多信息。)

    这是我编写的一个实用程序脚本,用于以较少破坏性的方式向我的%PATH%添加目录。它还可以避免将同一目录多次添加到%PATH%,无论其格式如何(例如尾部反斜杠,相对路径,环境变量或任何其他排列)。

    @echo off
    setlocal enabledelayedexpansion
    
    if not exist "%~1" goto usage
    
    for %%I in ("%~1") do pushd "%%~I" 2>NUL && (set "new=!CD!" && popd) || goto usage
    for %%I in ("%PATH:;=";"%") do pushd "%%~I" 2>NUL && (
        rem // delaying expansion of !new! prevents parentheses from breaking things
        if /i "!new!"=="!CD!" (
            echo !new! already exists in %%PATH%%
            goto :EOF
        )
        popd
    )
    
    call :append_path "%new%"
    
    goto :EOF
    
    :usage
    echo Usage: %~nx0 "dir"
    goto :EOF
    
    :append_path <val>
    set "env=HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
    for /f "tokens=2*" %%I in ('reg query "%env%" /v Path ^| findstr /i "\<Path\>"') do (
    
        rem // make addition persistent through reboots
        reg add "%env%" /f /v Path /t REG_EXPAND_SZ /d "%%J;%~1"
    
        rem // apply change to the current process
        for %%a in ("%%J;%~1") do path %%~a
    )
    
    rem // use setx to set a temporary throwaway value to trigger a WM_SETTINGCHANGE
    rem // applies change to new console windows without requiring a reboot
    (setx /m foo bar & reg delete "%env%" /f /v foo) >NUL 2>NUL
    
    color 4E
    echo Warning: %%PATH%% has changed.  Reopen the console to inherit the changes.
    
    goto :EOF
    

答案 1 :(得分:1)

  1. 这就是Setx所做的。请参阅Setx /?,告诉您这一点。它将其永久地添加到用户的环境中(除非使用/ m)。但是%PATH%是根据系统和用户环境的PATH构建的(在32位窗口上也是autoexec.bat,如果通过ShellExecute启动,也是App Paths reg键))

  2. 不要担心。如果%PATH%中已存在路径,则Setx不会将路径添加到%PATH%。

  3. 为什么要重新定义系统变量%COMSPEC%。