¿Cómo establecer la variable de entorno PATH en el archivo por lotes solo una vez en Windows?

Tengo un archivo por lotes que establece la ruta del usuario y se ejecuta como parte del paso de comstackción IDE de Visual Studio.

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

Cuando construyo el proyecto, cierro VS, lo vuelvo a abrir y lo reconstruyo, veo una ruta adjunta como parte de la variable PATH . Sin embargo, veo que en la configuración de Windows de la variable de entorno, la variable PATH se crea bajo variables de entorno de usuario como

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

Pregunta 1:

¿Por qué esta ruta también aparece como ruta adjunta como parte de la variable de entorno del sistema?

Al ejecutar echo %PATH% través de la consola de Visual Studio (cuando ejecuto el proyecto por segunda vez), imprimo la ruta de la variable del sistema y agregué la nueva ruta que creé.

Pregunta 2:

Quiero modificar mi archivo por lotes para que solo establezca una PATH entorno PATH en la configuración del usuario durante la primera ejecución de la comstackción de Visual Studio. Si la variable de usuario PATH ya existe en ejecuciones posteriores, no debería ejecutar el comando set nuevamente para evitar agregar una nueva ruta una y otra vez en la variable del sistema.

¿Alguna idea de cómo lograr esto?

editar: después de algunas pruebas, parece que mi respuesta original no es del todo aplicable a las preguntas de OP. Para responder OP más directamente:

  1. %PATH% combina los valores en HKLM\System\CurrentControlSet\Control\Session Manager\Environment\Path con HKCU\Environment\Path . Cuando setx "dir;dir" , lo que está configurando es el valor de la Path HKEY_CURRENT_USER . El valor de la Path HKEY_LOCAL_MACHINE toda la máquina permanece intacto. Es por eso que ve sus valores como adjuntos, en lugar de como reemplazos. Tendría que usar setx /m para reemplazar el valor de la Path HKLM . Pero no lo haga a menos que desee crear problemas graves con la instalación de su sistema operativo.

  2. Si desea probar si existe un directorio en %PATH% , puede pushd o pushd ambos en el directorio que desea verificar y en cada directorio dentro de %PATH% para unificar cada uno, asegurándose de que todas las rutas relativas, variables de entorno, etc. son aplastados set "var=%CD%" para cada uno. Entonces, if /I "!dir1!"=="!dir2!" el directorio ya existe en algún lugar en %PATH% . Hay un ejemplo de esto en mi respuesta original a continuación.

La razón por la que mi respuesta original no es totalmente aplicable es porque setx sí misma no es tan destructivo como una vez pensé. El peligro es que muchas veces cuando los usuarios quieren agregar un directorio a su ruta, establecerán setx /m PATH "%PATH%;new dir" ; y eso es destructivo Como %PATH% se expande antes de que setx escriba el valor, todos los directorios en PATH se expanden prematuramente.

El siguiente método sería más seguro:

 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" 

Pero eso no fue realmente lo que OP preguntó, y me disculpo por la respuesta instintiva.


respuesta original: setx es destructivo y no debe usarse de esta manera. Cuando setx PATH , está convirtiendo el tipo de datos de valor de registro de REG_EXPAND_SZ a REG_SZ. En cuanto lo haga, todas las variables de entorno dynamic almacenadas en%% PATH% se convertirán en rutas planas y absolutas. Use el comando de path para agregar directorios a su %PATH% temporalmente, y reg add para hacerlo permanentemente. (Como nota al margen, también hay dpath , que agrega temporalmente un directorio a su ruta de acceso, pero solo puede ser utilizado por el comando de type . Desplácese 2/3 hacia abajo en esta página para obtener más información sobre dpath ).

Aquí hay un script de utilidad que escribí para agregar directorios a mi %PATH% de una manera menos destructiva. También evitará agregar el mismo directorio a %PATH% más de una vez, independientemente de cómo esté formateado (por ejemplo, barra diagonal inversa, rutas relativas, variables de entorno o cualquier otra permutación).

 @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  set "env=HKLM\System\CurrentControlSet\Control\Session Manager\Environment" for /f "tokens=2*" %%I in ('reg query "%env%" /v Path ^| findstr /i "\"') 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. Eso es lo que hace Setx. Ver Setx /? donde te dice esto Lo agrega al entorno del usuario permanentemente (a menos que se use / m). Sin embargo,% PATH% se genera desde el sistema y la ruta del entorno del usuario (y también autoexec.bat en ventanas de 32 bits y si se inicia a través de ShellExecute también la clave reg de rutas de acceso de aplicaciones))

  2. No te preocupes Setx no agrega rutas a% PATH% si ya existen en% PATH%.

¿Por qué está redefiniendo la variable del sistema% COMSPEC%?