在Windows上将目录添加到PATH环境变量的最佳做法是什么?

rbl8hiat  于 2023-11-21  发布在  Windows
关注(0)|答案(1)|浏览(201)

我正在编写一个Windows应用程序。作为此应用程序的一部分,我想在安装时修改用户的PATH变量。我希望使用任何.bat命令来完成此操作,但我对任何不涉及第三方软件或不强制用户重新启动计算机的可能性感兴趣。如果有任何帮助,我将使用NSIS进行安装。
我知道setx。然而,使用它似乎有一个1024 character limit,虽然这是可以克服的,我更担心在PATH中丢失对环境变量的引用。请参阅Harry约翰斯顿在this thread中对这个问题的评论。我能找到的所有资源都是旧的,还有一些人们宣传的软件包,例如pathed。但是,在不使用第三方软件的情况下,是否真的没有安全的方法来更新windows上的PATH变量?
在我链接的第一个线程上也有一个涉及使用PowerShell的路线,但是这不会有Harry约翰斯顿在他的评论中提到的同样的限制吗?该路由也被称为here,该线程上的答案要绕过setx的1024个字符限制,需要用户重新启动计算机,我宁愿避免这种情况。解决方法包括设置一个变量本身来触发广播消息,但是对于我们重置的随机变量来说,1024个字符的限制不还是一个问题吗?更不用说这感觉相当不好。
改变路径似乎是一件应该是常见的事情,这样做的最佳实践是什么?

gblwokeq

gblwokeq1#

我写了几个批处理文件的过程来添加或删除一个文件夹路径到usersystem环境变量PATH,见these answers,但我还没有找到一个解决方案,真正工作的每一个可能的文件夹路径添加或PATH变量的每一个可能的现有值使用一个批处理文件,只有Windows commands
需要处理的一些问题包括:
1.要添加的文件夹路径包含分号,需要添加用"括起来的文件夹路径,以获得有效的分号分隔的文件夹路径列表。
1.要添加的文件夹路径包含一个等号,这使得在使用批处理文件时,检查该文件夹路径是否已存在于环境变量PATH的值中变得非常困难,甚至可能是不可能的。
1.现有的PATH值已经包含一个"中的文件夹路径,原因可能是文件夹路径包含;或其他安装程序,或者用户操作不当,不必要地添加了一个带有双引号的文件夹路径。
1.已经存在的PATH值已经包含一个带有等号的文件夹路径,这使得检查要添加的文件夹路径是否已经存在于环境变量PATH的值中变得非常困难,甚至可能是不可能的。
1.Windows Command Processorcmd.exe处理批处理文件时,默认情况下使用每个字符一个字节的编码,并根据国家/地区使用OEM代码页。这是一个问题,尤其是在亚洲国家,用户经常使用他们的真实的姓名作为用户帐户名,因此环境变量USERNAMEUSERPROFILE包含Unicode编码在 *Windows命令处理器 * 使用的代码页中根本没有可用的字符。在这种使用情况下,使用批处理文件更新usersystem环境变量PATH可能会损坏现有的PATH值。
Windows应用程序或脚本的开发人员应始终考虑避免向usersystem环境变量PATH添加文件夹路径的设计。始终可以在编写应用程序和脚本时不向usersystem添加文件夹路径环境变量PATH。由安装程序存储以供已安装的应用程序或脚本使用的文件夹路径也可以存储在Windows注册表中注册表项Software\CompanyName\ProgramName下的其他位置在HKEY_CURRENT_USER中(当前用户)或HKEY_LOCAL_MACHINE(所有用户)以及存储在%APPDATA%\CompanyName\ProgramName目录下的配置文件中(当前用户)或%ALLUSERSPROFILE%\CompanyName\ProgramName(所有用户)。如果程序/脚本依赖于添加到usersystem的文件夹路径,则通常表示应用程序/脚本设计不正确环境变量PATH以确保正常工作。
仅当用户很可能主要从控制台中使用应用程序/脚本时,才应在安装过程中向usersystem环境变量PATH添加文件夹路径(Windows命令提示符、PowerShell控制台、Windows终端),方法是键入不带文件扩展名的文件名以及各种参数,并且仅在安装期间询问用户是否应将应用程序/脚本文件夹路径添加到usersystem环境变量PATH以便于使用应用程序/脚本文件夹路径之后脚本。用户可能不经常使用应用程序/脚本,因此不希望将应用程序/脚本的文件夹路径从控制台添加到用户系统环境变量PATH,它影响许多其他应用程序和脚本的执行时间,并使文件系统访问次数增加近每一个过程。
使用由cmd.exe仅使用 *Windows命令处理器 * 的内部命令和其他Windows命令处理的批处理文件的主要问题是,cmd.exe是为执行命令和可执行文件而设计的,而不是为字符串处理而设计的,而字符串处理由更现代、功能更强大的脚本解释器(如 Windows Script HostPowerShell)提供本机支持。这使得处理诸如PATH的持久性存储环境变量的现有值,以便使用用户定义的文件夹路径或用户的帐户配置来更新它成为一个噩梦。现有的PATH值以及要添加的文件夹路径可能包含对 * 命令处理器 * 具有特殊意义的字符。这使得纯批处理文件解决方案很难真正用于任何可能的用例,甚至是不可能的。

这里是一个注解的批处理脚本,适用于将文件夹路径添加到user环境变量PATH的常见用例。它甚至可以在Windows XP上工作,其中SETX根本不可用,并且仅在结果值不超过1024个字符限制时使用SETX。否则使用命令REG来更新注册表值,其缺点是Windows shell不会收到有关user环境变量PATH更改的消息。对于更新的user,用户必须至少登录/注销并重新登录/登录环境变量PATH对用户帐户下运行的所有进程生效。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PathToAdd=C:\Temp\Development & Test not 100%% (!)"

set "UserPath="
for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\System32\reg.exe query HKCU\Environment /v Path 2^>nul') do (
    if /I "%%G" == "Path" (
        set "UserPath=%%I"
        if defined UserPath goto ProcessPath
    )
)

rem The folder path to add should not be enclosed in double quotes, except
rem on containing a semicolon, must contain \ (backslash) as directory
rem separator and not / (slash), and should not end with a backslash. A
rem path to add with a semicolon or with an equal sign is not supported
rem by this batch code. There is an error messages output to inform the
rem user about this limitation and suggesting adding the folder path
rem manually to the user environment variable PATH.
:ProcessPath
set "PathToAdd=%PathToAdd:"=%"
set "PathToAdd=%PathToAdd:/=\%"
if "%PathToAdd:~-1%" == "\" set "PathToAdd=%PathToAdd:~0,-1%"
if not "%PathToAdd:;=%" == "%PathToAdd%" set "ErrorChar=;" & goto ErrorAdd
for /F "eol=| tokens=1 delims==" %%I in ("%PathToAdd%") do if not "%%I" == "%PathToAdd%" set "ErrorChar==" & goto ErrorAdd

setlocal EnableDelayedExpansion
rem Is the user environment variable PATH not present or has an empty value?
if not defined UserPath set "PathToSet=!PathToAdd!" & goto UpdatePath
endlocal

rem It is also not possible to add a folder path to the user environment
rem variable PATH if this variable as stored in the registry contains
rem already a folder path with an equal sign or enclosed in double quotes.
set "PathCheck=%UserPath:"=%"
for /F "eol=| tokens=1 delims==" %%I in ("%PathCheck%") do if not "%%I" == "%PathCheck%" set "ErrorChar==" & goto ErrorPath
setlocal EnableDelayedExpansion
if "!PathCheck!" == "!UserPath!" goto CheckPath
endlocal
set "ErrorChar=""
goto ErrorPath

rem Determine if the user environment variable PATH ends already
rem with a semicolon in which case no additional semicolon must
rem be added left to the folder path to add.
:CheckPath
if "!UserPath:~-1!" == ";" (set "Separator=") else set "Separator=;"
set "PathCheck=!UserPath!%Separator%"

rem Do nothing if the folder path to add without or with a backslash
rem at end with a semicolon appended for entire folder path check is
rem already in the user PATH value. This code does not work on path
rem to add contains an equal sign which is fortunately very rare.
if not "!PathCheck:%PathToAdd%;=!" == "!PathCheck!" goto EndBatch
if not "!PathCheck:%PathToAdd%\;=!" == "!PathCheck!" goto EndBatch
set "PathToSet=!UserPath!%Separator%!PathToAdd!"

:UpdatePath
set "UseSetx=1"
if not "!PathToSet:~1024,1!" == "" set "UseSetx="
if not exist %SystemRoot%\System32\setx.exe set "UseSetx="
if defined UseSetx (
    %SystemRoot%\System32\setx.exe Path "!PathToSet!" >nul
) else (
    set "ValueType=REG_EXPAND_SZ"
    if "!PathToSet:%%=!" == "!PathToSet!" set "ValueType=REG_SZ"
    %SystemRoot%\System32\reg.exe ADD  HKCU\Environment /f /v Path /t !ValueType! /d "!PathToSet!" >nul
)
goto EndBatch

:ErrorAdd
echo(
echo ERROR: Folder path to add to user environment variable PATH is:
echo(
setlocal EnableDelayedExpansion
if "%ErrorChar%" == ";"  (echo "!PathToAdd!") else echo !PathToAdd!
echo(
echo The folder path contains the character '%ErrorChar%' which is not supported
echo by this procedure for updating the user environment variable PATH.
goto Suggestion

:ErrorPath
echo(
echo ERROR: Folder path to add to user environment variable PATH is:
echo(
setlocal EnableDelayedExpansion
echo !PathToAdd!
echo(
echo The user environment variable PATH contains the character '%ErrorChar%'.
echo This procedure for updating the user environment variable PATH
echo does not support updating the variable PATH with that character.
:Suggestion
echo(
echo The folder path must be manually added to the user environment variable PATH.
echo Please click on Windows Start button, type on keyboard the word environment,
echo and click on suggested item "Edit environment variables for your account".
echo Add or edit the environment variable PATH in the upper list of user
echo environment variables and append the folder path as displayed here.
echo(
pause

:EndBatch
endlocal
endlocal

字符串

**注意:**环境变量PathToAdd必须在此批处理文件的第三行根据需要定义。

更新user环境变量PATH的前四个问题由此脚本处理,不更新持久存储的环境变量,而是通知用户原因以及用户现在应该做什么来将文件夹路径添加到user环境变量PATH
第五个问题是缺少对要添加的路径或user环境变量PATH的现有值中包含Unicode字符的文件夹路径的支持,此批处理文件根本无法处理。
检查要添加的文件夹路径是否已经存在于userPATH的值中,这是非常糟糕的,因为这是通过简单的不区分大小写的字符串比较完成的。可能是要添加的文件夹路径使用像%APPDATA%\Python这样的变量引用作为值,而相同的文件夹路径已经存在于userPATH值以扩展的形式出现,如C:\Users\UserName\AppData\Roaming\Python。这在用户使用错误编码的安装程序时非常常见,该安装程序使用所有环境变量的扩展来更新持久存储的环境变量PATH,而不是保留环境变量引用。上面的批处理代码会将文件夹路径添加到持久存储的user环境变量PATH由于%APPDATA%\Python而不存在于包含C:\Users\UserName\AppData\Roaming\Python的现有值中。
如果安装是由用户从命令提示符窗口启动的,即一个已经在运行的cmd.exe进程,则在安装过程中更新user环境变量PATH的批处理文件在退出批处理文件处理之前,还应该在任何本地环境设置之外通过命令SETSTANDARD更新local环境变量PATH
另外,最好检查用户使用的控制台是否是真实的,从批处理文件中的PowerShell控制台是通过%ComSpec% /c ""Fully qualified batch file name""的隐式执行的。在这种情况下,应通知用户必须关闭PowerShell控制台窗口,并从Windows shell打开一个新窗口(Windows桌面,Windows开始菜单,如果由于命令REG而不需要登录/注销和登录/登录或完全重新启动Windows,用于更新持久存储的环境变量,而不是SETX
依赖于本地中特定文件夹路径的应用程序/脚本PATH应始终通知用户在安装后重新启动Windows,在卸载后分别将文件夹路径添加到永久存储的PATH中,并从永久存储的PATH中删除文件夹路径,然后再执行其他操作,以确保修改后的PATH真正有效for the processes流程.
用户不喜欢在安装或卸载应用程序/脚本后重新启动Windows,并且经常忽略该建议或请求。但是这些用户接下来经常抱怨刚刚安装的应用程序无法正常工作,并向其他人寻求帮助,例如在Stack Overflow上。这样的应用程序/脚本的开发人员可以避免在使用应用程序/脚本的设计时遇到的许多麻烦。不依赖于安装过程中添加到PATH的文件夹路径的脚本。
要了解所使用的命令及其工作方式,请打开command prompt窗口,在那里执行以下命令,并仔细阅读显示的每个命令的帮助页面。

  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • pause /?
  • reg /?
  • reg add /?
  • reg query /?
  • rem /?
  • set /?
  • setlocal /?
  • setx /?

有关2>nul的解释,请阅读有关Using command redirection operators的Microsoft文档。在执行命令FOR之前,Windows命令解释器处理第一个FOR命令行时,必须使用插入字符^对重定向运算符>进行转义,以将其解释为文字字符它使用在后台启动的单独命令进程执行嵌入式reg命令行,并将'中的命令行作为附加参数附加。
另请参阅:

相关问题