【问题标题】:How to update PATH variable permanently from Windows command line?如何从 Windows 命令行永久更新 PATH 变量?
【发布时间】:2012-01-11 14:19:19
【问题描述】:

如果我从命令行 (cmd.exe) 执行 set PATH=%PATH%;C:\\Something\\bin,然后执行 echo %PATH%,我会看到此字符串已添加到 PATH。如果我关闭并打开命令行,则该新字符串不在 PATH 中。

我怎样才能从命令行为将来的所有进程永久更新 PATH,而不仅仅是当前进程?

我不想通过转到系统属性 → 高级 → 环境变量并在那里更新 PATH 来执行此操作。

此命令必须从 Java 应用程序执行(请参阅我的另一个 question)。

【问题讨论】:

标签: java windows cmd path


【解决方案1】:

你可以使用:

setx PATH "%PATH%;C:\\Something\\bin"

但是,setx 会将存储的字符串截断为 1024 字节,可能会损坏 PATH。

/M 将更改HKEY_LOCAL_MACHINE 中的PATH 而不是HKEY_CURRENT_USER。换句话说,一个系统变量,而不是用户的。例如:

SETX /M PATH "%PATH%;C:\your path with spaces"

您必须记住,新的 PATH 在您当前的cmd.exe 中不可见。

但是,如果您查看注册表或使用"set p" 查找新的cmd.exe,您可以看到新值。

【讨论】:

  • 有没有办法使用setx改变机器的路径而不是用户的路径?
  • here你可以看出,在windows xp上,通过在命令末尾使用/m,不仅可以为当前登录的用户设置变量,还可以为机器设置一个变量和 7. 不过我还没试过。
  • 运行setx命令时出现错误“默认选项不允许超过'2'时间”如何绕过它?
  • @KilgoreCod cmets:我警告不要使用以下命令:在许多(大多数?)安装中,这些天 PATH 变量会很长 - setx 会将存储的字符串截断为 1024 字节,可能会损坏 PATH (请参阅此处的讨论superuser.com/q/812754)。
  • 我尝试回显已经超过 1200 字节的路径。任何其他方式来代替 setx?
【解决方案2】:

有关如何执行此操作的文档可以在 MSDN 上找到。关键摘录是这样的:

要以编程方式添加或修改系统环境变量,请将它们添加到 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment 注册表项,然后广播 WM_SETTINGCHANGE 消息并将 lParam 设置为字符串“环境”。这允许应用程序(例如 shell)获取您的更新。

请注意,您的应用程序需要提升管理员权限才能修改此密钥。

您在 cmets 中表明您很乐意仅修改每个用户的环境。通过编辑 HKEY_CURRENT_USER\Environment 中的值来执行此操作。和以前一样,请确保您广播了 WM_SETTINGCHANGE 消息。

您应该能够使用 JNI 注册表类轻松地在 Java 应用程序中执行此操作。

【讨论】:

  • 是的,使用 JNI 注册表类。一个更大的问题是您的应用程序可能没有运行提升。你知道如何让它做到这一点吗?如果您只希望应用程序的一小部分运行提升(即只是为了进行此更改),那么最简单的解决方案是一个非常简单的 C++ 应用程序来完成这项工作,用应用程序清单标记,然后作为一个单独的进程执行引发 UAC 对话。
  • 您也可以编辑HKEY_CURRENT_USER\Environment 以避免海拔要求。
  • @David Heffernan 是的,只有这个东西必须提升。所以你的建议是编写 C++ 应用程序并从我的 java 应用程序中执行它?您能否提供一些示例代码或链接来说明如何执行此操作?
  • 是的。正如大卫所说。只有你不抬高。我还应该提到这只会修改当前用户的环境。
  • 您需要将其分离到一个单独的进程中,以便在修改系统 PATH 时仅强制执行 UAC 对话框。它只需要一个简单的 C++ 应用程序,其中包含一些注册表读取和写入,然后是一个 SendMessage。在应用清单中将requestedExecutionLevel 设置为requireAdministrator
【解决方案3】:

我警告不要使用该命令

setx PATH "%PATH%;C:\Something\bin"

修改 PATH 变量,因为其实现的“特性”。在当今的许多(大多数?)安装中,变量会很长 - setx 会将存储的字符串截断为 1024 字节,可能会破坏 PATH(参见讨论 here)。

我专门注册以标记此问题,因此缺乏直接评论 12 年 5 月 2 日发布的答案的网站声誉。感谢 beresfordt 添加这样的评论

【讨论】:

    【解决方案4】:

    这个 Python 脚本[*] 正是这样做的:

    """
    Show/Modify/Append registry env-vars (ie `PATH`) and notify Windows-applications to pickup changes.
    
    First attempts to show/modify HKEY_LOCAL_MACHINE (all users), and 
    if not accessible due to admin-rights missing, fails-back 
    to HKEY_CURRENT_USER.
    Write and Delete operations do not proceed to user-tree if all-users succeed.
    
    Syntax: 
        {prog}                  : Print all env-vars. 
        {prog}  VARNAME         : Print value for VARNAME. 
        {prog}  VARNAME   VALUE : Set VALUE for VARNAME. 
        {prog}  +VARNAME  VALUE : Append VALUE in VARNAME delimeted with ';' (i.e. used for `PATH`). 
        {prog}  -VARNAME        : Delete env-var value. 
    
    Note that the current command-window will not be affected, 
    changes would apply only for new command-windows.
    """
    
    import winreg
    import os, sys, win32gui, win32con
    
    def reg_key(tree, path, varname):
        return '%s\%s:%s' % (tree, path, varname) 
    
    def reg_entry(tree, path, varname, value):
        return '%s=%s' % (reg_key(tree, path, varname), value)
    
    def query_value(key, varname):
        value, type_id = winreg.QueryValueEx(key, varname)
        return value
    
    def yield_all_entries(tree, path, key):
        i = 0
        while True:
            try:
                n,v,t = winreg.EnumValue(key, i)
                yield reg_entry(tree, path, n, v)
                i += 1
            except OSError:
                break ## Expected, this is how iteration ends.
    
    def notify_windows(action, tree, path, varname, value):
        win32gui.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')
        print("---%s %s" % (action, reg_entry(tree, path, varname, value)), file=sys.stderr)
    
    def manage_registry_env_vars(varname=None, value=None):
        reg_keys = [
            ('HKEY_LOCAL_MACHINE', r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'),
            ('HKEY_CURRENT_USER', r'Environment'),
        ]
        for (tree_name, path) in reg_keys:
            tree = eval('winreg.%s'%tree_name)
            try:
                with winreg.ConnectRegistry(None, tree) as reg:
                    with winreg.OpenKey(reg, path, 0, winreg.KEY_ALL_ACCESS) as key:
                        if not varname:
                            for regent in yield_all_entries(tree_name, path, key):
                                print(regent)
                        else:
                            if not value:
                                if varname.startswith('-'):
                                    varname = varname[1:]
                                    value = query_value(key, varname)
                                    winreg.DeleteValue(key, varname)
                                    notify_windows("Deleted", tree_name, path, varname, value)
                                    break  ## Don't propagate into user-tree.
                                else:
                                    value = query_value(key, varname)
                                    print(reg_entry(tree_name, path, varname, value))
                            else:
                                if varname.startswith('+'):
                                    varname = varname[1:]
                                    value = query_value(key, varname) + ';' + value
                                winreg.SetValueEx(key, varname, 0, winreg.REG_EXPAND_SZ, value)
                                notify_windows("Updated", tree_name, path, varname, value)
                                break  ## Don't propagate into user-tree.
            except PermissionError as ex:
                print("!!!Cannot access %s due to: %s" % 
                        (reg_key(tree_name, path, varname), ex), file=sys.stderr)
            except FileNotFoundError as ex:
                print("!!!Cannot find %s due to: %s" % 
                        (reg_key(tree_name, path, varname), ex), file=sys.stderr)
    
    if __name__=='__main__':
        args = sys.argv
        argc = len(args)
        if argc > 3:
            print(__doc__.format(prog=args[0]), file=sys.stderr)
            sys.exit()
    
        manage_registry_env_vars(*args[1:])
    

    以下是一些使用示例,假设它已保存在您当前路径某处名为setenv.py 的文件中。 请注意,在这些示例中,我没有管理员权限,因此这些更改仅影响我的本地用户的注册表树:

    > REM ## Print all env-vars
    > setenv.py
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    HKEY_CURRENT_USER\Environment:PATH=...
    ...
    
    > REM ## Query env-var:
    > setenv.py PATH C:\foo
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    !!!Cannot find HKEY_CURRENT_USER\Environment:PATH due to: [WinError 2] The system cannot find the file specified
    
    > REM ## Set env-var:
    > setenv.py PATH C:\foo
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    ---Set HKEY_CURRENT_USER\Environment:PATH=C:\foo
    
    > REM ## Append env-var:
    > setenv.py +PATH D:\Bar
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    ---Set HKEY_CURRENT_USER\Environment:PATH=C:\foo;D:\Bar
    
    > REM ## Delete env-var:
    > setenv.py -PATH
    !!!Cannot access HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session   Manager\Environment:PATH due to: [WinError 5] Access is denied
    ---Deleted HKEY_CURRENT_USER\Environment:PATH
    

    [*] 改编自:http://code.activestate.com/recipes/416087-persistent-environment-variables-on-windows/

    【讨论】:

      【解决方案5】:

      出于参考目的,对于任何搜索如何通过代码更改路径的人,我在此网页上引用了 Delphi 程序员的一篇有用的帖子:http://www.tek-tips.com/viewthread.cfm?qid=686382

      TonHu (Programmer) 22 Oct 03 17:57 I found where I read the original 发帖,在这里: http://news.jrsoftware.org/news/innosetup.isx/msg02129....

      您需要的摘录如下:

      您必须在 LParam 中指定字符串“Environment”。在德尔福你会 这样做:

       SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, Integer(PChar('Environment')));
      

      这是由 Jordan Russell 建议的,http://www.jrsoftware.org, (a.o.) InnoSetup 的作者,(“Inno Setup 是 Windows 程序。 Inno Setup 于 1997 年首次推出,如今可与竞争对手媲美 甚至在功能集上超过了许多商业安装程序和 稳定性。”)(我只是希望更多人使用 InnoSetup )

      HTH

      【讨论】:

      【解决方案6】:

      在企业网络中,用户只有有限的访问权限并使用便携式应用程序,有以下命令行技巧:

      1. 查询用户环境变量:reg query "HKEY_CURRENT_USER\Environment"。将 "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" 用于 LOCAL_MACHINE。
      2. 添加新的用户环境变量:reg add "HKEY_CURRENT_USER\Environment" /v shared_dir /d "c:\shared" /t REG_SZ。对包含其他 %% 变量的路径使用 REG_EXPAND_SZ
      3. 删除现有环境变量:reg delete "HKEY_CURRENT_USER\Environment" /v shared_dir

      【讨论】:

        【解决方案7】:

        这个脚本 http://www.autohotkey.com/board/topic/63210-modify-system-path-gui/

        包括所有必要的 Windows API 调用,可以根据您的需要进行重构。它实际上是一个 AutoHotkey GUI,可以轻松更改系统路径。需要以管理员身份运行。

        【讨论】:

        • 很棒的剧本。我使用 HotKey,但不知道如何或需要做什么才能将脚本添加到其中。您能提供帮助、提供链接或解释需要做什么吗?
        猜你喜欢
        • 2023-04-04
        • 2014-08-04
        • 1970-01-01
        • 2015-04-27
        • 1970-01-01
        • 2012-08-09
        • 2011-04-07
        • 2019-05-24
        • 2021-06-22
        相关资源
        最近更新 更多