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

122
我想知道您在管理系统可执行文件时使用的方法。例如,我几乎可以通过命令行访问所有内容,但现在我已经达到了路径字符串的限制,因此我无法添加任何其他目录。
那么你有什么建议吗? 很久以前,我尝试在属于路径的目录中使用可执行文件的软链接,但那种方法并没有起作用。 将“仅可执行文件”放入已知目录中会出现问题,因为几乎所有应用程序都需要一组文件,因此这也不太好。 将可执行文件及其所有文件放入已知目录中,这可能有效,但是文件名称冲突的可能性非常高。 创建一个硬链接?我不知道。您认为呢?

为什么你使用了这么多路径?路径通常用于共享目录,当你的应用程序必须与其他人共享扩展对象/应用程序/库时。使用太多会使应用程序启动变慢。你能否详细说明如何使用,创建路径环境变量? - pinichi
1
嗨Pinichi,很多应用程序使用标准的“C:\ Program File \ AppNAme \ ...”,在我的情况下,许多这些应用程序可以以命令行方式运行或需要对其他应用程序可访问(例如Miktex的可执行文件,任何Tex编辑器都希望存在),因此它们需要在PATH中。我想知道更好的方法,因为我的方法是不可持续的。 - mjsr
1
这个工具将压缩路径。结果令人印象深刻:http://www.uweraabe.de/Blog/2014/09/09/the-garbled-path-variable/#more-337 - Gabriel
12个回答

88

这将解析您的%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变量。


2
这也很有用,因为它告诉我关于随着时间累积而存在的所有不存在的目录在我的路径中。 - Nate Glenn
27
Rapid Environment Editor是另一种实现此操作的方式。它会突出显示不存在的目录,并提供“将长路径转换为短路径”的选项。 - Russell Gallop
3
先生,那是一个很棒的工具。 - elo80ka
1
请注意,在 %%~sa 后缺少闭合引号。我尝试更新回答,但除非更改6个字符,否则无法进行。 - zr870
我希望我可以投多次赞。我知道这个答案是在“被采纳的答案”之后近3年才出现的,但如果我是楼主,我会改变我的想法并将其作为被采纳的答案! - Andrew Steitz
显示剩余4条评论

85

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

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%的长度,因为它们在存储之前会被展开。这可能是真的,我没有进行测试。但是,另一种选择是对长目录名称使用8.3形式,例如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%
作为一般规则,你应该小心从互联网运行批处理文件,因为批处理文件可以做各种事情,比如格式化硬盘。如果你不信任上面的代码(由我编写),你可以通过替换该行来进行测试。
%actualdir%\%actualfile% %args%

使用

echo %actualdir%\%actualfile% %args%
理想情况下,在运行每一行代码之前,您应该确切知道它的作用。

1
8点3格式很好用,但对于真正大的目录来说并不太适合,例如“C:\Program Files (x86)\Microsoft Visual Studio 2008 SDK\VisualStudioIntegration\Tools\Sandcastle\ProductionTools"。另一个节省一点的方法是,作为用户,我可以基于系统路径创建一个PATH变量,并添加任何其他目录。所有这些方法都属于“压缩该字符串”类型,但我们能否像Unix一样拥有一个集中的二进制目录呢? - mjsr
2
谢谢Mitch,您提供的Edit 4正是我想要的!现在我可以拥有一个集中的文件夹,其中包含我需要的所有二进制文件。我将深入测试以查看某些应用程序是否存在问题。 - mjsr
2
你的“编辑4”部分在传递参数给可执行文件方面过于复杂。请参考Michael Burr的回答。 - Dave Andersen
1
不确定为什么这个回答会被投票得这么高。原始回答和第2、3次编辑提供的解决方案是错误的。第1和4次编辑提供了一个过于复杂和脆弱的版本,而其他回答中已经正确地解决了这个问题。回答者似乎对问题所涉及的问题几乎完全无知。 - jwg
1
创建一个带有快捷方式的bin文件夹是否比批处理文件更好?特别是因为它们使用更少的空间,并且可以像.exe文件一样处理参数。 - jiggunjer
显示剩余9条评论

29
如果您使用的是Windows Vista或更高版本,您可以创建一个到文件夹的符号链接。例如: mklink /d C:\pf "C:\Program Files" 这将创建一个链接,使得 c:\pf 成为您的 program files 文件夹。使用此技巧可以从我的路径中删减300个字符。

这是一个不错的选择,可以代替使用环境变量来表示部分路径。 - porcus
1
这肯定会更有帮助,但如果您想要一个更“正确”(受支持的?)的解决方案,您可以将 c:\Program Filesc:\Program Files (x86) 的实例替换为预定义变量 %ProgramFiles%%ProgramFiles(x86)%。http://www.tenforums.com/tutorials/3234-environment-variables-windows-10-a.html 这些只能节省几个字符,但如果您真的快要达到 PATH 的最大值,这可能会有所不同。 说到这一点,我将创建 %pf% 和 %pfx%,它们将解析为正确的路径。感谢您的建议! :) - rainabba
使用类似%pf%和%pfx%这样的变量存在的问题是,您会遇到与创建符号链接相同的问题-软件更新可能会再次将东西添加到路径变量中。使用这种方式的另一个问题是,它不是快速轻松地在脚本中操作或从资源管理器中浏览。如果按照我所描述的方法,您可以直接打开c:\PF。Windows将其视为文件夹,因此您可以很容易地编写bat或powershell来对其进行操作。 - bmg002

11

如果有人感兴趣的话...

我发现我从来不需要一次性使用所有路径,所以我创建了一堆“初始化”批处理文件,根据需要修改路径。

例如,如果我想在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%

我认为这种方法相对简洁,且尚未遇到任何问题。


8

通常我不需要担心这个问题(我甚至不知道现代Windows系统上的路径大小限制是什么),但以下是我可能采取的方法,以避免将程序目录添加到路径中:

  • most command line utilities get thrown into a c:\util directory that's on the path
  • otherwise, I'll add a simple cmd/batch file to the c:\util directory that looks something like:

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

这条命令本质上创建了一个别名(alias)。它并不完美,有些程序可能会坚持要在路径(path)中(现在很少见),而其他试图调用它的程序可能无法正确找到它。但对于大多数情况,它都能正常工作。

总的来说,我一般不需要担心避免将目录添加到路径中。


当你开始遵循这个“路径”时,请注意批处理脚本不能在没有“CALL [bat]”语法的情况下调用另一个批处理脚本。因此,如果您想确保您转发或未转发的exe是从bat中调用的,请使用“call php script.php”而不是仅使用“php script.php”(两种方式都可以工作)。 使用.bat分派程序的一个很好的理由是防止PATH名称冲突(同一exe的多个版本)。 - 131
@131:您能解释一下您所说的“这个‘路径’”是什么意思吗?您是指示例中的特定文件路径吗?还是指这个答案提出的一般方法? - O. R. Mapper
@O.R.Mapper:当131说“当你开始遵循这个‘路径’”时,他的意思是“当你使用这种技术”。 - Michael Burr
1
正如你所写的,“试图调用它的其他程序可能无法正确找到它” - 一个例子是:不幸的是,它可以抛出对命令行应用程序的自动调用,例如通过构建工具(如NAnt)。一种解决方法是在命令前加上cmd /c,但这反过来又意味着构建脚本变成了Windows特定的:/我已经在单独的问题中询问了这个问题。 - O. R. Mapper

5
另一个想法:使用DIR /X来确定非8点3文件名生成的短名称,然后在%PATH%中使用这些名称。
例如,'C:\Program Files'变成'C:\PROGRA~1'。

1
抱歉,我刚意识到这个建议已经被 @Mitch 提出了。我会给他点赞的 :) - Android Eve

5

3
我编写并经常使用一个标准流(stdin/stderr/stdout)和退出代码代理程序(称为dispatcher https://github.com/131/dispatcher)。
我使用的所有CLI程序(node、php、python、git、svn、rsync、plink等)实际上都是相同的可执行文件(约10kb),我只是给它们不同的名称,并将它们放在同一个目录中。一个虚拟的静态明文文件用于“代理文件名到真正的可执行文件映射”。
Dispatcher使用低级别的进程管理win32 API,以保证绝对透明。
使用这个软件,我只需要在我的PATH中设置一个附加目录,就可以使用所有可能需要的程序。

1

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

编辑:

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


1
我认为路径会包含扩展变量,如果是这样的话,它就不会变得更短。 - Ben Voigt

0

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

  1. 为不同的软件包使用组合创建不同的用户。 例如:(a) 创建一个名为web的用户,以提供所有Web开发软件;(b) 创建一个名为database的用户,以提供所有数据库和数据仓库软件包。请记住,有些软件可能会创建多个条目。或者有时我将其分成Oracle特定、MSSQL特定和Oracle特定用户。我将MySQL/PostgreSQL、Tomcat、Wamp、Xamp全部放入用户帐户webr中。

  2. 如果可能,将常用软件包(如Office、Photoshop等)安装为系统特定,供所有用户使用,将特殊软件包安装为用户特定。当然,我必须登录不同的用户并安装它们。并非所有软件都提供此选项。如果“仅为此用户安装”选项不可用,请为整个系统安装。

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

  4. 如果所有上述步骤都通过了Windows限制,请包括任何批处理以替换缩写链接到路径。

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接