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

use*_*783 2 batch-file

我有批处理文件,用于设置用户路径,并作为Visual Studio IDE构建步骤的一部分运行.

@ECHO OFF
@ECHO %PATH%
set COMSPEC = "%VCINSTALLDIR%\vcvarsall.bat" amd64
setx PATH "..\..\lib\libsndfile;..\..\lib\simulink" 
@ECHO %PATH%
Run Code Online (Sandbox Code Playgroud)

当我构建项目,关闭VS,并重新打开它,并重建时,我将附加路径视为PATH变量的一部分.但是,我看到在Windows环境中设置环境变量PATH变量是在用户环境变量下创建的

..\..\lib\libsndfile;..\..\lib\simulink
Run Code Online (Sandbox Code Playgroud)

问题1:

为什么此路径也作为附加路径显示为系统环境变量的一部分?

echo %PATH%通过Visual Studio控制台执行时(当我第二次运行项目时)打印系统变量路径和我创建的新路径附加到它.

问题2:

我想修改我的批处理文件,以便它只PATH在首次运行Visual Studio构建期间在用户设置中设置一次环境变量.如果用户变量PATH在后续运行中已存在,则不应再次执行set命令以避免在系统变量中反复添加新路径.

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

roj*_*ojo 6

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

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

  2. 如果要测试目录是否存在%PATH%,您可以cd或者pushd同时检查要检查的目录和每个目录,%PATH%以统一每个目录,确保所有相对路径,环境变量等都是平坦的. set "var=%CD%"为每个人.然后if /I "!dir1!"=="!dir2!"该目录已存在于某处%PATH%.我在下面的原始答案中有一个例子.

我原来的答案不完全适用的原因是因为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"
Run Code Online (Sandbox Code Playgroud)

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


原始答案: setx具有破坏性,不应该以这种方式使用.当您setx PATH将注册表值数据类型从REG_EXPAND_SZ转换为REG_SZ时.一旦执行此操作,存储在%PATH%中的所有动态环境变量都将转换为平坦的绝对路径.使用该path命令%PATH%暂时将目录附加到您的目录,并reg add永久地执行此操作.(作为旁注,还有dpath,它会暂时在您的路径中添加一个目录,但只能由type命令使用.在此页面的下方滚动2/3以获取更多信息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
Run Code Online (Sandbox Code Playgroud)