如何避免在 Windows 中过度填充 PATH 环境变量?

Posted

技术标签:

【中文标题】如何避免在 Windows 中过度填充 PATH 环境变量?【英文标题】:How do you avoid over-populating the PATH Environment Variable in Windows? 【发布时间】:2011-05-23 05:59:32 【问题描述】:

我想知道您使用哪些方法来管理系统中的可执行文件。例如,我几乎可以通过命令行访问所有内容,但现在我遇到了路径字符串的限制,所以我不能再添加任何目录了。

那你有什么推荐的? 很久以前,我尝试在属于路径的目录中使用可执行文件的软链接,但这种方法不起作用。 将“executable only”扔到一个已知的Dir,几乎所有应用程序都需要一组文件的问题,所以这也很糟糕。 将可执行文件和他的所有文件扔到一个已知的目录中,嗯,这会起作用,但是文件名发生冲突的可能性非常高。 创建硬链接?我不知道。你怎么看?

【问题讨论】:

为什么要使用这么多路径?当您的应用程序必须与其他人共享扩展对象/应用程序/lib 时,路径通常用于公共目录。使用太多会使应用程序启动速度变慢。您能否详细说明如何使用、创建路径环境变量? 嗨 pinichi,很多应用程序使用标准的“C:\Program File\AppNAme\...”,在我的例子中,很多应用程序可以以命令行方式运行,或者需要其他应用程序可以访问(例如,任何 Tex 编辑器都期望存在的 Miktex 的可执行文件),因此它们需要位于 PATH 中。我不知道更好的方法,因为我的方法不可持续 这个工具会压缩路径。结果令人印象深刻:uweraabe.de/Blog/2014/09/09/the-garbled-path-variable/#more-337 【参考方案1】:

这将解析您的 %PATH% 环境变量并将每个目录转换为其等效的短名称,然后将它们重新组合在一起:

@echo off

SET MyPath=%PATH%
echo %MyPath%
echo --

setlocal EnableDelayedExpansion

SET TempPath="%MyPath:;=";"%"
SET var=
FOR %%a IN (%TempPath%) DO (
    IF exist %%~sa (
        SET "var=!var!;%%~sa"
    ) ELSE (
        echo %%a does not exist
    )
)

echo --
echo !var:~1!

获取输出并更新环境变量中的 PATH 变量。

【讨论】:

谢谢你,非常有用!!它缩短了我从 1990 年到 1338 年的道路,一切仍然像魅力一样运作!我选择了您的方法,因为我想将所有内容都保留在我的路径中,并且通过批处理文件进行链接会太耗时。谢谢! 这也很有用,因为它告诉我路径中所有不存在的目录随着时间​​的推移而累积。 快速环境编辑器是另一种方法。它突出显示不存在的目录,并有一个选项“将长路径转换为短路径”。 @RussellGallop:先生,这是一个很棒的工具。 请注意%%~sa 后面缺少的结束引号。我试图更新答案,但除非我更改 6 个字符,否则它不会让我这样做【参考方案2】:

我能想到的一种方法是使用其他环境变量来存储部分路径;例如,如果你有

C:\this_is_a\long_path\that_appears\in_multiple_places\subdir1;
C:\this_is_a\long_path\that_appears\in_multiple_places\subdir2;

然后你可以创建一个新的环境变量如

SET P1=C:\this_is_a\long_path\that_appears\in_multiple_places

之后您的原始路径变为

%P1%\subdir1;
%P1%\subdir2;

编辑:另一种选择是创建一个bin 目录,其中包含指向相应.exe 文件的.bat 文件。

编辑 2: Ben Voigt 对另一个答案的评论提到,按照建议使用其他环境变量可能不会减少 %PATH% 的长度,因为它们会在存储之前被扩展。这可能是真的,我还没有测试过。不过,另一种选择是使用 8dot3 格式来表示更长的目录名称,例如 C:\Program Files 通常等同于 C:\PROGRA~1。您可以使用dir /x 查看较短的名称。

编辑 3:这个简单的测试让我相信 Ben Voigt 是对的。

set test1=hello
set test2=%test1%hello
set test1=bye
echo %test2%

在此结束时,您会看到输出 hellohello 而不是 byehello

编辑 4: 如果您决定使用批处理文件来消除 %PATH% 中的某些路径,您可能会担心如何将参数从批处理文件传递到可执行文件,以便过程是透明的(即,您不会注意到调用批处理文件和调用可执行文件之间有任何区别)。我没有很多编写批处理文件的经验,但这似乎工作正常。

@echo off

rem This batch file points to an executable of the same name
rem that is located in another directory. Specify the directory
rem here:

set actualdir=c:\this_is\an_example_path

rem You do not need to change anything that follows.

set actualfile=%0
set args=%1
:beginloop
if "%1" == "" goto endloop
shift
set args=%args% %1
goto beginloop
:endloop
%actualdir%\%actualfile% %args%

一般来说,从 Internet 运行批处理文件时应小心谨慎,因为您可以对批处理文件执行各种操作,例如格式化硬盘驱动器。如果你不相信上面的代码(我写的),你可以通过替换行来测试它

%actualdir%\%actualfile% %args%

echo %actualdir%\%actualfile% %args%

理想情况下,您应该在运行前准确了解每行的作用。

【讨论】:

8dot3 形式效果很好,但对于真正大的目录来说并不是太大,例如“C:\Program Files (x86)\Microsoft Visual Studio 2008 SDK\VisualStudioIntegration\Tools\Sandcastle\ProductionTools \"。另一件节省一点的事情是,作为用户,我可以基于系统路径创建一个 PATH 变量,并添加任何其他目录。所有这些方法都是“压缩字符串”类型,但是我们可以像 Unix 那样拥有一个集中的二进制目录吗? 嗯,对于很长的目录,我认为恰恰相反:目录越长,使用 8dot3 格式保存的字符越多。如果难以在cmd 中导航,请注意您可以使用* 来节省输入。例如,从根目录输入dir /x pro*。您将在那里看到您想要的目录及其 8dot3 名称。然后使用cd 导航到它并重复该过程。 关于 UNIX,$PATH 与 Windows 中的 %PATH% 工作方式非常相似,所以我不确定您的意思是什么。按照惯例,UNIX 目录名称往往比 Windows 中的更短,因此$PATH 也往往更短。 感谢 Mitch,您提供的 Edit 4 正是我想要的!现在我可以拥有包含所有我需要的二进制文件的集中文件夹。我将进行更深入的测试,看看某些应用程序是否存在问题 您的“编辑 4”部分过于复杂,无法将参数传递给可执行文件。请参阅 Michael Burr 的回答。【参考方案3】:

如果您使用的是 windows vista 或更高版本,您可以创建指向该文件夹的符号链接。例如:

mklink /d C:\pf "C:\Program Files"

会创建一个链接,所以c:\pf 将成为您的program files 文件夹。通过使用这个技巧,我从路径中减少了 300 个字符。

【讨论】:

这是使用环境变量表示部分路径的一个很好的替代方案。 这肯定会更有帮助,但如果您想要一个更“正确”(支持?)的解决方案,您可以用预定义变量 @ 替换 c:\Program Filesc:\Program Files (x86) 的实例987654327@ 和 %ProgramFiles(x86)% tenforums.com/tutorials/… 这些每个只保存几个字符,但如果你真的处于最大化 PATH 的边缘,那可能会有所不同。就此而言,我将创建解析为正确路径的 %pf% 和 %pfx%。谢谢你的主意! :) 使用 %pf% 和 %pfx% 等变量的问题在于,您会遇到与创建符号链接相同的问题 - 软件更新可能会再次向路径变量添加内容。使用这样的变量的另一个问题是,围绕它编写脚本或从资源管理器浏览到它们并不快速和容易。使用我描述的方法,您可以直接打开 c:\PF。 Windows 将它视为一个文件夹,因此您也可以很容易地针对它编写 bat 或 powershell。【参考方案4】:

如果有人感兴趣...

我发现我从来没有真正需要所有这些路径,所以我创建了一堆“初始化”批处理文件,它们会相应地修改路径。

例如,如果我想在 Eclipse 中进行一些 C++ 开发,我会这样做:

> initmingw
> initeclipse
> eclipse

这对于避免同名可执行文件之间的冲突也很方便(例如 C++ 和 D 编译器,它们都有一个 make.exe)。

我的批处理文件通常如下所示:

@echo off
set PATH=C:\Path\To\My\Stuff1;%PATH%
set PATH=C:\Path\To\My\Stuff2;%PATH%

我觉得这种方法比较干净,而且还没有遇到任何问题。

【讨论】:

【参考方案5】:

我通常不必担心这个(我没有遇到路径大小限制 - 我什至不知道在现代 Windows 系统上是什么),但为了避免放置路径中的程序目录:

大多数命令行实用程序都会被扔到路径上的 c:\util 目录中

否则,我将在c:\util 目录中添加一个简单的 cmd/batch 文件,如下所示:

@"c:\program files\whereever\foo.exe" %*

本质上为命令创建了一个别名。它不一定是完美的。有些程序确实坚持要在路径中(这在现在非常罕见),而其他尝试调用它的程序可能无法正确找到它。但对于大多数用途来说,它运作良好。

但一般来说,我不必担心避免将目录添加到路径中。

【讨论】:

当您开始遵循此“路径”时,请注意批处理脚本无法在没有“CALL [bat]”语法的情况下调用另一个批处理脚本。因此,如果您想确保从 bat 调用转发或不转发的 exe,请使用“调用 php script.php”而不仅仅是“php script.php”(这两种方式都适用)使用 . bat dispatcher是为了防止PATH名字冲突(同一个exe的多个版本) @131:您介意解释一下“这条“路径””是什么意思吗?您是指示例中的特定文件路径吗?或者更确切地说,这个答案建议的一般方法? @O.R.Mapper:当 131 说,'当你开始遵循这条“路径”时',他的意思是,'当你使用这种技术时'。 正如您所写,“尝试调用它的其他程序可能无法正确找到它” - 例如:不幸的是,它可以自动调用命令行应用程序,例如通过构建工具,例如南特,当然。一种补救方法是调用带有前置 cmd /c 的命令,但这反过来意味着构建脚本成为 Windows 特定的:/ 我在 separate question 中询问过这个问题。【参考方案6】:

另一个思路:使用 DIR /X 确定为非 8dot3 文件生成的短名称 名字。然后在你的 %PATH% 中使用这些。

例如,'C:\Program Files' 变为 'C:\PROGRA~1'。

【讨论】:

糟糕,我刚刚意识到@Mitch 已经建议了这一点。我要为此给他+1。 :)【参考方案7】:

使用 App Path 注册表项而不是应用程序特定路径的路径变量:

http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx

【讨论】:

【参考方案8】:

我每次都编写和使用标准流(stdin/stderr/stdout)和退出代码代理程序(称为调度程序https://github.com/131/dispatcher)

我使用的所有 CLI 程序(node、php、python、git、svn、rsync、plink ...)实际上是同一个 exe 文件(大约 10kb,我只是命名不同),我把在同一目录中。一个虚拟的静态明文文件执行“代理文件名到真实 exe 映射”。

Dispatcher 使用底层进程管理 win32 API 以实现绝对透明。

使用这个软件,我只在我的 PATH 中为我可能使用的所有程序设置了一个附加目录。

【讨论】:

【参考方案9】:

创建一个文件夹 c:\bin 添加到您的路径并像您说的那样进行硬链接可以缩短字符串。也许将变量 pf 添加到值为 c:\Program Files 的系统变量,然后在路径中用 %pf% 替换 c:\Program Files。

编辑:

创建一个虚拟驱动器。 subst p: "c:\program 文件"

【讨论】:

我认为路径将包含扩展变量,在这种情况下它不会变得更短。【参考方案10】:

我按照以下步骤使条目易于管理:

    为不同的软件包组合使用创建了不同的用户。 示例: (a) 创建了一个用户网络,以提供所有网络开发软件; (b) 创建用户数据库,以提供所有数据库和数据仓库软件包。请记住,某些软件可能会创建多个条目。或者有时我将其分解为特定于 oracle 的用户和特定于 MSSQL 的用户以及特定于 oracle 的用户。我把mysql/PostgreSQL、tomcat、wamp、xamp都放到了用户账号webr中。

    如果可能的话,安装常见的软件包,如 office、photoshop、.. 作为系统特定的适用于所有用户,特殊软件包作为用户特定的。当然,我必须登录不同的用户并安装它们。并非所有软件都可以提供此选项。如果“仅为该用户安装”选项不可用,请为整个系统安装。

    我避免将程序安装到文件夹 Program File (x86) 或 Program File 中。我总是安装到基本目录中。例如 MySQL 64 位进入“C:\mysql64”,MySQL 32 位进入“C:\mysql”文件夹。我总是假设只为 64 位软件添加后缀 64。如果没有后缀,则为 32 位。我对 Java 和其他人也遵循同样的原则。这样我的路径会更短,不包括“C:\Program File (x86)”。对于某些软件,可能需要编辑配置文件以显示 .exe 文件的确切位置。只有需要安装到“C:\Program File (x86)”的程序才会安装到该文件夹​​中。我总是记得缩短名字。我避免使用像 tomcat/release/version-2.5.0.3 这样的详细信息。如果我需要知道版本,我会按名称版本创建一个文件并将其放入 tomcat 文件夹中。一般尽量缩短链接。

    如果上述所有步骤都超过了 Windows 限制,请包含任何批次以替换路径的缩写链接。

然后登录到特定用途(移动应用程序,或数据库/数据仓库或网络开发......)用户并执行相关任务。

您还可以在窗口中创建虚拟窗口。只要您拥有一份许可的操作系统副本,就可以使用相同的密钥创建多个虚拟窗口。您可以将特定于特定任务的包放在该机器中。您必须每次启动单独的虚拟机。一些内存密集型软件包,如 3D 动画电影制作器,都应该放在主机中,而不是放在 VM 中,因为 VM 将只有一部分 RAM 可供使用。但是,启动每个 VM 很痛苦。

【讨论】:

【参考方案11】:

上述解决方案仅在您可以缩减路径时才有效。就我而言,这并不是一个真正的选择,而且每次打开命令提示符时都必须运行脚本很麻烦。所以我写了一个简单的脚本,它会在打开命令提示符时自动运行,并将文本文件的内容附加到你的路径中。

在某些情况下,运行此脚本会破坏某些内容(例如,在 github 或 cygwin shell 中),因此我还添加了一个包含路径列表的文件,如果在其中启动命令提示符,则路径变量不会通过通常更新路径的启动脚本进行更改。

@echo off

:: Modify these to the actual paths of these two files
set dontSetupFile=C:\Users\Yams\Dontsetup.txt
set pathFile=C:\Users\Yams\Path.txt

:: Retrieve the current path (for determining whether or not we should append to our path)
set curDir=%cd%

:: Be done if the current path is listed in the dontSetupFile
SetLocal EnableDelayedExpansion
for /F "delims=" %%i in (%dontSetupFile%) do (
    if "%%i"=="%curDir%" GOTO AllDone
)



:: Append the pathFile to our current PATH
set pathAppend=
for /F "delims=" %%i in (%pathFile%) do (set pathAppend=!pathAppend!%%i)

set PATH=%PATH%;%pathAppend%


:: The only way to actually modify a command prompt's path via a batch file is by starting
::   up another command prompt window. So we will do this, however, if this script is
::   automatically called on startup of any command prompt window, it will infinately 
::   recurse and bad things will happen.

:: If we already ran, we are done
if "%yams%"=="onion" GOTO AllDone

:: Otherwise, flag that we just ran, and then start up a new command prompt window
::   with this flag set
set yams=onion

cmd \K set PATH=%PATH%;

:: When that command prompt exits, it will load back up this command prompt window, and
::   then the user will need to exit out of this as well. This causes this window to
::   automatically exit once the cmd it just spawned is closed.
exit()

:: Path is set up, we are done!
:AllDone
@echo on

Path.txt 看起来像

C:\Program Files (x86)\Google\google_appengine;
C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;
C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;
C:\Program Files\Microsoft SQL Server\110\Tools\Binn;
C:\Program Files\Microsoft DNX\Dnvm;
C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit;

虽然 Dontsetup.txt 看起来像

C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit
C:\Program Files (x86)\Git\cmd
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin

要让它在启动时自动运行,请打开 regedit,导航到 HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Command Processor,然后右键单击右侧并按新建 -> 多字符串值。将其命名为自动运行。将其值设置为

C:\Users\Yams\setUpPath.bat

或您在上面存储批处理文件的其他任何地方。

【讨论】:

【参考方案12】:

没有尝试过,但是将 PATH 拆分成部分工作并将它们加入最终变量工作吗?

例如,最初假设您有类似的东西

PATH=LONGPATH1;LONGPATH2;....2048th char....LONGPATH_N-1;LONGPATH_N

相反,您创建:

_PATH1 = LONGPATH1;LONGPATH2;....2048 char
_PATH2 = 2049th char...LONGPATH_N-1;LONGPATH_N
rem // may be more parts
PATH = %_PATH1%;%_PATH2%

【讨论】:

以上是关于如何避免在 Windows 中过度填充 PATH 环境变量?的主要内容,如果未能解决你的问题,请参考以下文章

在构建 Java GraphQL API 时,如何避免从数据库中过度获取(即仅获取查询中指定的字段)?

如何使用随机森林对不平衡类进行分类以避免过度拟合

避免过度拟合之正则化(转)

如何检查过度绘制

数据库分库分表如何避免“过度设计”和“过早优化”

iOS 7 过度导航栏按钮填充