如何避免在 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 Files
和 c:\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 环境变量?的主要内容,如果未能解决你的问题,请参考以下文章