42

Scope: Windows XP or newer Tools: Batch script

I need to be able to remove an unneeded path name from the system %PATH% variable. I know how to add a new path name to the system %PATH% variable, using a tool such as SETX.EXE, which also makes it immediately available within the existing CMD environment. It's probably a matter of using FIND and/or a FOR loop of some kind, but I'm not quite sure how to accomplish this. Here's a sample path statement...

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

From this, I need to be able to remove the full path name related to "oracle." So, in the above example, I need to be able to remove the "C:\oracle\product\10.2.0\bin" from the above path statement. Unfortunately, not only could the oracle path name be different than shown above, there could be multiple oracle path names and all need to be removed. I tried implementing the solution here...

How can I extract a full path from the PATH environment variable?

However, it just isn't working. The script wouldn't find the path name. Any help would be appreciated. Thank you.

Community
  • 1
  • 1
user3208239
  • 691
  • 1
  • 7
  • 15

8 Answers8

82

This removes the substring C:\Program Files (x86)\Git\bin; from the PATH string and re-assigns:

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

You might use this to see the change:

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

Note: be exact on the substring. It's case-sensitive and slash-sensitive.

If you need to make it a persistent change use setx instead of set and open another console for changes to take effect.

setx /M PATH "%PATH:C:\Program Files (x86)\Git\bin;=%"
Jens A. Koch
  • 39,862
  • 13
  • 113
  • 141
10

You can try something like this :

@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!

I putted an echo to the last line. Check the result and If it's OK for you, remove it.

SachaDee
  • 9,245
  • 3
  • 23
  • 33
  • Wait...that only works for the current user session. I tried using setx with the -m option to assign the path statement system wide, but to no avail. Even though the echo shows the correct path, when setting it instead of echoing it, it still only displays it. When I echo %path%, it still shows the original, unmodified system path. Any other ideas? Thanks. – user3208239 Jan 22 '14 at 20:29
  • 1
    Try like this : `reg.exe ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d !newpath! /f` – SachaDee Jan 22 '14 at 21:34
  • With my path that led to setting the path = "/f". I re-ordered like this and fixed the variable name: `reg.exe ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /f /d "!$newpath:~1!"` . For me it still didn't work, so I added this `reg.exe ADD "HKEY_CURRENT_USER\Environment" /v Path /t REG_EXPAND_SZ /f /d "!$newpath:~1!"`. This works after logging off and on again. Not sure why SETX doesn't work for some of us here, I suspect in my case because the path is very long. – lessthanideal May 14 '18 at 11:12
  • It is a length limitation. See https://superuser.com/questions/387619/overcoming-the-1024-character-limit-with-setx , I found the powershell solution worked fine. – lessthanideal May 14 '18 at 11:37
9

After trying SachaDee's answers I got errors with paths like

C:\Program Files (x86)

with brackets: Program Files (x86)\Directory gave me

Directorywas unexpected at this time. (no matter what time I tried it)

I added

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

before the for-loop and

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

after the loop (not sure if it is necessary)

@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!

And it is now working.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Joe
  • 119
  • 1
  • 4
  • I found that I had to add another change to make the change persist to the calling shell. Since there is no `endlocal` the change to the path variable is lost when the script exits. If this is not what you want, change the last line to: `endlocal & set path=%$newpath:~1%` Note that it _must_ be on one line, and that it uses `%` instead of `!`. – MikeG Feb 18 '21 at 14:17
  • This is the one that works! is there a way to suppress the console outputs? e.g. I get all the matches output to the console ... – SkyWalker Mar 11 '21 at 16:26
  • @SkyWalker Even with `@echo off`? Did you try to add `>nul` to the line that caused the output? – Joe Mar 12 '21 at 10:57
2

I found the other solutions to this problem a bit awkward, I don't really want to rely on exact paths, complex 'delayed expansion' syntax, removing spaces for the 'for /f' loop and then adding them back in...

I think this is more elegant, and I commented the hell out of it so even someone new to the horrors of Batch can follow along.

::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
Vopel
  • 662
  • 6
  • 11
0

I use this in CYGWIN to filter out CYGWIN paths before starting some Windows commands:

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

I'm quite sure it's easy to adapt to Windows-native perl and bat files. Advantage: the flexible power of regular expressions.

user1050755
  • 11,218
  • 4
  • 45
  • 56
0

I wanted to remove %LocalAppData%\Microsoft\WindowsApps; from PATH. But this was not possible due to using a another variable in the environment variable for Windows. The CALL hack is worked in SS64. (Also, thanks to Jens A. Koch for the base command.)

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

Of course, the PATH changing by SET will not be permanent. For fixed change, it is necessary to use the SETX command or directly change the entries in the Registry.

Actually, this solution was not needed to delete %LocalAppData%\Microsoft\WindowsApps; from PATH.

The %LocalAppData%\Microsoft\WindowsApps; is stored in the PATH entry of the Registry's HKCU\Environment key. Although it is more practical to delete this entry with the REG DELETE command, if there are another directories in the PATH entry, they will also be deleted, so new solution is needed.

I failed to remove the %USERPROFILE% variable syntax from SET (The %% symbol dilemma). Fortunately, PShell came to the rescue:

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)"

Special thanks to vonpryz for the last command. Because PowerShell's [System.Environment]::SetEnvironmentVariable command saves variables to Registry as REG_SZ even if their original value type is REG_EXPAND_SZ, which it's the known issue.

pureocean
  • 61
  • 3
0

I wrote this code to simply remove any python executeable path from the path variable, and insert my own specefic python version in the path so i can run python with the versoin i wanted.

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

also, the first line is important! don't remove it or it wont work.

Notice: this code must run from a batch ".bat" file , if u want to copy paste this code in cmd window, you must replace all "%%a" to "%a" in this code.

0

If you know a file that exists within the directory you want to remove (e.g. want to remove all paths that might include java.exe), the following will work very straightforwardly by simply doing string replacement, no need to parse the path, etc:

@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
Jimbly
  • 348
  • 2
  • 5