通过批处理从%path%变量中删除不需要的路径名

43

范围:Windows XP或更新版本 工具:批处理

我需要能够从系统%PATH%变量中删除一个不必要的路径名。 我知道如何使用诸如SETX.EXE之类的工具将新路径名添加到系统%PATH%变量中,并使其立即在现有CMD环境中可用。 这可能涉及使用FIND和/或某种FOR循环,但我不太确定如何完成此操作。这是一个示例路径语句...

%PATH% = C:\;C:\Program Files\Common Files\Java;C:\oracle\product\10.2.0\bin;C:\WINDOWS;C:\WINDOWS\system32;

因此,我需要能够删除与“oracle”相关的完整路径名。因此,在上面的示例中,我需要能够从上面的路径语句中删除“C:\oracle\product\10.2.0\bin”。不幸的是,oracle路径名称不仅可能与上面显示的不同,而且可能有多个oracle路径名称,所有这些都需要被删除。我尝试在此处实现解决方案...

如何从PATH环境变量中提取完整路径?

然而,它并没有奏效。脚本无法找到路径名称。任何帮助将不胜感激。谢谢。

8个回答

83

这将从PATH字符串中删除子字符串C:\Program Files (x86)\Git\bin;并重新分配:

set PATH=%PATH:C:\Program Files (x86)\Git\bin;=%

你可以使用这个来查看变化:

echo %PATH:C:\Program Files (x86)\Git\bin;=% | tr ; \n

注意:在子字符串上要精确匹配,区分大小写并且敏感于斜杠。

如果您需要进行持久更改,请使用setx而不是set,并打开另一个控制台以使更改生效。

setx /M PATH "%PATH:C:\Program Files (x86)\Git\bin;=%"

1
完美地满足了我的需求! - Ale
2
"setx /M PATH "%PATH:C:\Program Files (x86)\Git\bin;=%"" - uriel
1
关于语法,参考这里(https://ss64.com/nt/syntax-replace.html)。 - IcyBrk
传奇。这应该是正确的答案。 - dbokers
1
注意:使用 /M 标志将会把本地用户的 PATH 元素复制到全局设置中。这将影响所有用户。对于当前用户,它可能会创建重复的 PATH 元素。 - proski
显示剩余6条评论

10

你可以尝试类似这样的方法:

@echo off&cls
setlocal EnableDelayedExpansion
set $line=%path%
set $line=%$line: =#%
set $line=%$line:;= %

for %%a in (%$line%) do echo %%a | find /i "oracle" || set $newpath=!$newpath!;%%a
set $newpath=!$newpath:#= !
echo set path=!$newpath:~1!

我在最后一行添加了一个echo。请检查结果,如果你认为可以的话,就将其删除。


等等...那只适用于当前用户会话。我尝试使用setx和-m选项来分配系统范围的路径语句,但没有成功。尽管回显显示了正确的路径,但是当将其设置而不是回显时,它仍然只显示它。当我回显%path%时,它仍然显示原始未修改的系统路径。还有其他想法吗?谢谢。 - user3208239
1
试试这样做:reg.exe ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d !newpath! /f - SachaDee
通过我的路径,我将路径设置为“/f”。我重新排序并修复了变量名称:reg.exe ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /f /d "!$newpath:~1!"。对我来说,它仍然无法正常工作,所以我添加了这个reg.exe ADD "HKEY_CURRENT_USER\Environment" /v Path /t REG_EXPAND_SZ /f /d "!$newpath:~1!"。在注销并再次登录后,这将起作用。不确定为什么SETX在我们中的某些人身上不起作用,我怀疑在我的情况下是因为路径非常长。 - lessthanideal
这是一个长度限制。请参见 https://superuser.com/questions/387619/overcoming-the-1024-character-limit-with-setx ,我发现 PowerShell 解决方案效果很好。 - lessthanideal

9

尝试使用SachaDee的答案后,我发现像路径这样的错误:

C:\Program Files (x86)

带括号的路径:Program Files (x86)\Directory 给出了如下错误:

Directory在此时是不被预期的。 (无论我什么时候尝试它)

我添加了:

set $line=%$line:)=^^)%

在for循环之前和

set $newpath=!$newpath:^^=!

循环后面的部分(不确定是否必要)。
@echo off
setlocal EnableDelayedExpansion
set path
set $line=%path%
set $line=%$line: =#%
set $line=%$line:;= %
set $line=%$line:)=^^)%

for %%a in (%$line%) do echo %%a | find /i "oracle" || set $newpath=!$newpath!;%%a
set $newpath=!$newpath:#= !
set $newpath=!$newpath:^^=!
set path=!$newpath:~1!

现在它正在工作。


我发现我必须添加另一个更改才能使更改持续到调用的 shell。由于没有 endlocal,当脚本退出时,对路径变量的更改会丢失。如果这不是您想要的,请将最后一行更改为: endlocal & set path=%$newpath:~1% 请注意,它 必须 在一行上,并且使用 % 而不是 ! - MikeG
这是有效的!有没有办法抑制控制台输出?例如,我将所有匹配项输出到控制台... - SkyWalker
@SkyWalker 即使使用 @echo off 也是这样吗? 你尝试在导致输出的行末添加 >nul 吗? - Joe

2
我发现其他解决此问题的方法有些笨拙,我不想依赖于精确路径、复杂的“延迟扩展”语法、移除“for /f”循环中的空格,然后再添加回来……
我认为这更加优雅,并且我对它进行了详细的注释,即使是新手也可以跟着操作。
::Turn off command display and allows environmental variables to be overridden for the current session
@echo off & setlocal

::Creates a unique file to use for the 'for loop'
set "TMPFILE="%temp%\tmp%RANDOM%%RANDOM%.txt""

::Duplicate PATH into OLDPATH
set "OLDPATH=%PATH%"

::Declare label for the 'goto' command
:Loop

::Extract the first text token with the default delimiter of semicolon
for /f "tokens=1 delims=;" %%G in ("%OLDPATH%") do (

REM Copy text token to TMPFILE unless what we want to remove is found
<NUL set /p="%%G" | find /i "StRiNgThAtMaTcHeSwHaTtOrEmOvE" >NUL 2>&1 || <NUL set /p="%%G;" >>%TMPFILE%

REM Remove text token from OLDPATH
set "OLDPATH=%OLDPATH:*;=%"
)

::Repeat loop until OLDPATH no longer has any delimiters, and then add any remaining value to TMPFILE
echo %OLDPATH% | findstr /C:";" >NUL && (goto :Loop) || <NUL set /p="%OLDPATH%" >>%TMPFILE%

::Set the path to TMPFILE
for /f "usebackq delims=" %%G in (%TMPFILE%) do (set "PATH=%%G")

::Clean-up
del %TMPFILE% >NUL 2>&1

::An echo and pause just for debug purposes
echo %PATH%
pause

“NUL” 这个东西到底是怎么工作的?赞一个好代码,谢谢。 - Cadoiz

0

我在CYGWIN中使用这个来过滤掉一些Windows命令之前的CYGWIN路径:

export PATH=`perl -e '@a=grep {$_ =~ /^\/cygdrive\//} split(":", $ENV{PATH});print join(":",@a)'`

我相信很容易适应于Windows本地的perl和bat文件。优点:正则表达式的灵活强大。


0
如果您知道存在于您想要删除的目录中的文件(例如,想要删除所有可能包含java.exe的路径),则可以通过简单地进行字符串替换来轻松完成以下操作,无需解析路径等:
@REM Executable to look for
set CMD=java.exe

:search
@REM Find the executable anywhere in the path
for %%a in (%CMD%) do set FOUND=%%~$PATH:a
if "%FOUND%"=="" goto done

@REM Strip \cmd.ext so we just have the directory
set FOUND=!FOUND:\%CMD%=!
@echo Found %CMD% in %FOUND%

@echo Removing %FOUND% from path...
set "PATH=!PATH:%FOUND%=!"

@REM Clean up any lone leftover \ in the path (in case the path was C:\foo\ instead of C:\foo)
set PATH=%PATH:;\;=;%

goto search
:done

0
我编写了这段代码,以便从路径变量中简单地删除任何Python可执行路径,并将我自己特定的Python版本插入到路径中,以便我可以使用我想要的版本运行Python。
setlocal enableDelayedExpansion 
set path`enter code here`
set $line=%path%
set $line=%$line: =#%
set $line=%$line:;= %
set $line=%$line:)=^^)%
set newpath=
for %%a in (%$line%)  do (
   echo %%a | find /i "python" ||set newpath=!newpath!;%%a
)
set path=!newpath!
set PATH=D:\python2.7\;%PATH%
@REM Rest of your script

python --version

@REM to exit the batch but not the window
exit /b

此外,第一行很重要!不要删除它,否则它将无法运行。

注意:此代码必须从批处理 ".bat" 文件中运行,如果您想要将此代码复制并粘贴到 cmd 窗口中,则必须在该代码中将所有 "%%a" 替换为 "%a"。


0

我想从PATH中删除%LocalAppData%\Microsoft\WindowsApps;。但由于在Windows环境变量中使用了另一个变量,这是不可能的。在SS64中,使用了CALL hack。(同时,感谢Jens A. Koch提供的基础命令。)

CALL set PATH=%PATH:%LocalAppData%\Microsoft\WindowsApps;=%

当然,使用SET更改的PATH不会是永久性的。要进行固定更改,需要使用SETX命令或直接更改注册表中的条目。

实际上,不需要从PATH中删除%LocalAppData%\Microsoft\WindowsApps;来解决问题。

%LocalAppData%\Microsoft\WindowsApps;存储在注册表的HKCU\Environment键的PATH条目中。虽然使用REG DELETE命令删除此条目更为实用,但如果PATH条目中有其他目录,则它们也将被删除,因此需要新的解决方案。

我无法从SET中删除%USERPROFILE%变量语法(%%符号的困境)。幸运的是,PShell提供了帮助:

SET userprofile= Powershell -c "$UserEnvironmentPath = [System.Environment]::GetEnvironmentVariable('Path', 'User'); $UserEnvironmentPath = $UserEnvironmentPath.Replace('%USERPROFILE%\AppData\Local\Microsoft\WindowsApps;',''); [Microsoft.Win32.Registry]::SetValue('HKEY_CURRENT_USER\Environment', 'Path', $UserEnvironmentPath, [Microsoft.Win32.RegistryValueKind]::ExpandString)"

特别感谢vonpryz提供的最后一条命令。因为PowerShell的[System.Environment] :: SetEnvironmentVariable命令将变量保存到注册表中,即使它们的原始值类型是REG_EXPAND_SZ,这是已知问题


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