V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hailan20220922
V2EX  ›  Windows

请教一下, windows 系统变量字符过长有什么好的解决方案!

  •  
  •   hailan20220922 · 58 天前 · 1236 次点击
    这是一个创建于 58 天前的主题,其中的信息可能已经有所发展或是发生改变。
    windows 系统变量内的的 path 因为我电脑内安装的软件和环境搭建已经超出字符限制,总提示过长,我网上查资料后将 path 内变量全部删除,添加$path1$,然后新建$path1$后将变量写入,以达到正常使用系统变量。但发现时间一长不知道为什么这种方法会失效,之后变量又全回到 path 内。网上查了半天不知道如何解决。不知道大家有什么好办法?
    9 条回复    2024-07-13 06:48:53 +08:00
    FengMubai
        1
    FengMubai  
       58 天前
    装个 python, 安装时会有个选项解除 path 长度限制
    geelaw
        2
    geelaw  
       58 天前 via iPhone   ❤️ 1
    @FengMubai #1 那个是去掉一些 API 里面路径长度的限制,和环境变量长度是两码事。

    这个问题比较无解,因为 PATH 是知名变量,如果希望 PATH 里面有所需要的路径,但需要的路径太多,则必然会超过长度限制。所谓回到 PATH 内,是指进程里面的 PATH 变长,还是用户级别的 PATH 变长,还是系统级别的 PATH 变长?第一种解决方法是时不时从一个干净的根进程重启其他进程;第二种、第三种要找出来是谁(哪个进程)在随意修改环境变量。
    hez2010
        3
    hez2010  
       58 天前
    环境变量长度限制只是那个编辑器 UI 以及命令行工具 setx 限制的,系统层面并没有限制环境变量长度。
    你可以绕过环境变量编辑器直接去注册表添加和修改环境变量。
    当前用户的环境变量:HKEY_CURRENT_USER\Environment
    系统的环境变量:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
    想要多长就能多长
    hailan20220922
        4
    hailan20220922  
    OP
       57 天前
    @hez2010 好的,谢谢,我研究一下。
    geelaw
        5
    geelaw  
       57 天前 via iPhone
    @hez2010 #3 然而这和文档说的相反,根据

    https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables

    环境变量的长度不能超过 32767 个字符。
    hez2010
        6
    hez2010  
       57 天前
    @geelaw 文档里写的这个限制是 practical limitation 。
    环境变量长度没有任何限制,之所以文档里写了限制那只是因为某些软件只能使用那么长的环境变量,而不代表系统不支持。
    同理,注册表实际上也并没有任何的长度限制,之所以文档里写了 key 的长度限制只是因为一些读写注册表的软件不支持那么长罢了。
    geelaw
        7
    geelaw  
       57 天前 via iPhone
    @hez2010 #6 我对英语的解读和你的不同,原文

    > The maximum size of a user-defined environment variable is 32,767 characters. There is no technical limitation on the size of the environment block. However, there are practical limits depending on the mechanism used to access the block. For example, a batch file cannot set a variable that is longer than the maximum command line length.

    说的是

    1. 一个环境变量不能超过 32767 个字符。
    2. 环境块没有限制。注意每个环境块是多个环境变量赋值的双空结尾字符串,这里说的是可以有任意多个环境变量。
    3. 访问环境块的方法会带来其他限制,
    4. 比如批处理文件不能设置环境变量的值为超过单行最大字符数长度的字符串。这个数是几千。

    待会儿我到电脑附近的时候可以试试。
    hez2010
        8
    hez2010  
       57 天前
    @geelaw 随手往注册表写了个 9w+长度的环境变量进去:

    ![img]( )

    可以看到 powershell 能够正常读出来并算出来长度,而 cmd 读不出来直接变成空了,但是环境变量放在那里没有任何的问题并且生效了。
    所以这个长度限制只是部分程序不支持那么长的环境变量,而不是系统本身不支持那么长的环境变量。
    geelaw
        9
    geelaw  
       57 天前   ❤️ 1
    @hez2010 #9 现象和规范是两码事,单纯做一个实验就认为 Windows 支持超长变量无异于依赖于 C++ undefined behavior 编程。

    应该注意 Win32 环境变量有两个存在的形式:在注册表里存储的系统/用户级变量、在每个进程里存储的进程级变量。

    考虑下面的每个实验,每个实验开始之前都不存在名字叫做 verylong 的系统、用户、进程级环境变量。

    ————

    实验 1:在 PowerShell 里运行

    [System.Environment]::SetEnvironmentVariable('verylong', '1'*40000, 'User')

    然后通过 explorer 打开一个新的 PowerShell ,并在新的 PowerShell 里运行

    $env:verylong.Length

    在 Windows 10 (build 19045.4651) x64 里得到的结果是 4095 ,这说明 explorer.exe 把 %verylong% 截断为 4095 个字符了。

    ————

    实验 2:在 PowerShell 里运行

    [System.Environment]::SetEnvironmentVariable('verylong', '1'*40000, 'User')
    $cred = Get-Credential
    Start-Process powershell -cred $cred -arg '-Command start powershell'

    输入当前用户的用户名和密码,然后等待新的 PowerShell 启动(注意这里需要两次跳转,似乎有不知名的 bug 导致单纯打开一次 PowerShell 无法输入),在新的 PowerShell 里面运行

    $env:verylong.Length

    得到 40000 ,这说明“什么都不做”似乎是可以自动读取超长环境变量,然而……

    ————

    实验 3:在 PowerShell 里运行

    [System.Environment]::SetEnvironmentVariable('verylong', '1'*40000) # 默认的范围是进程

    会得到

    Exception calling "SetEnvironmentVariable" with "2" argument(s): "Environment
    variable name or value is too long."

    查阅 PowerShell 的源代码,发现这个异常是从 Win32 API SetEnvironmentVariable https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setenvironmentvariable 来的(而不是 PowerShell 自己检查的),文档明确指出超过 32767 个字符是不支持的,实际调用也会返回 FALSE 并用 GetLastError 指示变量过长。

    ————

    实验 2 、3 表明实际上超过 32767 个字符的环境变量是不支持的,因为用于访问之的 Win32 API 拒绝设置超长变量。至于“什么都不做”的时候可以读到超长环境变量,单纯是 Windows 从注册表读取的时候、通过 GetEnvironmentVariable 返回的时候,忘记验证了。

    考虑不变式

    LPCTSTR name = T("verylong");
    TCHAR value[40001];
    DWORD size = 40001;
    DWORD actualSize = GetEnvironmentVariable(name, value, size);
    BOOL couldSet = SetEnvironmentVariable(name, value);

    自然期待单线程环境下 actualSize > 0 && actualSize < size (这表明获取名字是 verylong 的环境变量成功了)蕴涵着 couldSet (这表示可以做无意义且无害的赋值),但这个不变式因为 Windows 的实现很不小心所以不一定成立。

    然后,在做了上面的实验之后,我会认为日常使用的时候应该避免变量内容超过 4095 个字符,因为 Windows 最常见的 shell 即 explorer.exe 不支持超长的变量。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1057 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 23:20 · PVG 07:20 · LAX 16:20 · JFK 19:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.