1

I found a solution to remove a certain directory from the environment variable PATH directly via Windows commandline. But I would like to achieve the same result by issuing the command from within a cmd file.

What I can do is echoing the result I want to set PATH to if I put

echo %PATH:D:\dir-path;=%

into my cmd file. But if I write

set PATH=%PATH:D:\dir-path;=%

PATH contains only the directory I wanted to remove.

Furthermore I want to use a variable for the director path but if I try that the result is even worse. I put

set dirPath=D:\dir-path
echo %PATH:%dirPath%;=%

and all I get is dirPath;=.

I don't know how to fix this so I would be really grateful if someone could assist.

EDIT 1

As suggested by @Anders I now have:

@echo off

set exampleRemoveDir=d:\bar

REM If I use %exampleRemoveDir% it does not work at all.
call :removeFromPath exampleRemoveDir & set result=%ERRORLEVEL%

:removeFromPath
set removeDir=%~1

setlocal enableextensions enabledelayedexpansion
set _=!PATH:%removeDir%;=!
if "%_%" == "%PATH%" set _=!PATH:%removeDir%=!
endlocal & set PATH=%_%
echo %PATH%
exit /b 0

But with that solution PATH still remains unchanged. The code works flawlessly if I don't scope the removing step bit since I want to do that for multiple directories it would be a real pain to not have such a nice helper doing the work for me.

EDIT 2

Since this seems to be more complex than I thought here is my complete unchanged script so far.

@echo off
::  Switching Perl version from ActivePerl to StrawberryPerl or the other way round depending on which paths are set in
::  PATH.

::  Directories for ActivePerl
set activePerl_SiteBinPath=D:\ProgramFiles\ActivePerl\site\bin
set activePerl_BinPath=D:\ProgramFiles\ActivePerl\bin

::  Directories for StrawberryPerl
set strawberryPerl_SiteBinPath=D:\ProgramFiles\StrawberryPerl\perl\site\bin
set strawberryPerl_BinCPath=D:\ProgramFiles\StrawberryPerl\c\bin
set strawberryPerl_BinPath=D:\ProgramFiles\StrawberryPerl\perl\bin

:: Determine which of the directories are present in PATH and which are not.
call :isInPath %activePerl_SiteBinPath% & set foundActivePerl_SiteBinPath=%ERRORLEVEL%
call :isInPath %activePerl_BinPath% & set foundActivePerl_BinPath=%ERRORLEVEL%
call :isInPath %strawberryPerl_SiteBinPath% & set foundStrawberryPerl_SiteBinPath=%ERRORLEVEL%
call :isInPath %strawberryPerl_BinCPath% & set foundStrawberryPerl_BinCPath=%ERRORLEVEL%
call :isInPath %strawberryPerl_BinPath% & set foundStrawberryPerl_BinPath=%ERRORLEVEL%

:: Test
call :removeFromPath %strawberryPerl_SiteBinPath% & set removedStrawberryPerl_SiteBinPath=%ERRORLEVEL%

rem if /i %foundActivePerl_SiteBinPath% equ 0 if /i %foundActivePerl_BinPath% equ 0 (
rem     if /i %foundStrawberryPerl_SiteBinPath% neq 0 if /i %foundStrawberryPerl_BinPath% neq 0 if  /i %foundStrawberryPerl_BinCPath% neq 0 (
rem         echo Switching from ActivePerl to StrawberryPerl.
rem         TODO
rem         exit /b 0
rem     )
rem )
rem 
rem if /i %foundStrawberryPerl_SiteBinPath% equ 0 if /i %foundStrawberryPerl_BinPath% equ 0 if /i %foundStrawberryPerl_BinCPath% equ 0 (
rem     if /i %foundActivePerl_SiteBinPath% neq 0 if /i %foundActivePerl_BinPath% neq 0 (
rem         echo Switching from StrawberryPerl to ActivePerl.
rem         TODO
rem         exit /b 0
rem     )
rem )

:: Error
:: TODO
exit /b

:isInPath
::  Tests if the path stored within variable pathVar exists within %PATH%.
::
::  The result is returned as the ERRORLEVEL:
::      0 if the pathVar path is found in %PATH%.
::      1 if pathVar path is not found in %PATH%.
::      2 if parhVar path is missing or undefined.

:: Error checking
if "%~1"=="" exit /b 2

set pathVar=%~1

for /f %%i in ('echo ";%%PATH%%;" ^| find /c /i ";%pathVar%;"') do set /a foundPathVar=%%i

if /i %foundPathVar% equ 0 (
    exit /b 1
)
exit b/ 0

:removeFromPath
::  Removes a given directory from environment variable PATH if the directory exists within PATH.
::
::  The result is returned as the ERRORLEVEL:
::      0 if the given directory was removed from PATH or if it didn't exist in PATH.
::      1 if no directory was given or the directory is undefined.

:: Error checking
if "%~1"=="" exit /b 2

set removeDir=%~1

setlocal enableextensions enabledelayedexpansion
set _=!PATH:%removeDir%;=!
if "%_%" == "%PATH%" set _=!PATH:;%removeDir%=!
endlocal & set PATH=%_%
echo %PATH%

exit /b 0

EDIT 3

Thanks to @Anders removing the directory from path now works fine. I removed the wrong check for undefined parameter above and add % around the parameter of function calls. But somehow :isInPath now always returns zero. As far as I am concerned this already worked... :/ Furthermore, with the current code (added % to all function parameters) the cmd always directly closes irrespective of a pause after the call of :removeFromPath. It's infuriatingly!

Lilo
  • 341
  • 2
  • 14
  • Why are you wanting to remove a location from the `%PATH%` variable? Are you aware that any change you make using `SET "PATH=%PATH:match=replace%"` from within a batch/cmd.exe session is not prermanent, it lasts only as long as that cmd instance. Can you provide more of your batch file in order for us to get a better handle on what you are hoping to achieve. – Compo Sep 01 '17 at 12:51
  • @Lilo, do you have any other functions in your script that might cause issues? I tested Anders' script and it indeed does remove the dir from path. – Gerhard Sep 01 '17 at 13:28
  • In the long run I want to use setx but as long as it doesn't work with set why would I use setx? I have installed ActivePerl as well es StrawberryPerl and I want to be able to switch the currently used Perl variant by simply double clicking a batch script. To achieve that I have to check which directories are currently in PATH and thus have to be removed or added to switch from the currently used variant to the other. – Lilo Sep 01 '17 at 13:28
  • It will never work if you change %exampleRemoveDir% to exampleRemoveDir. In your edit you don't stop the script after call :removeFromPath and the regular part of the batch will sort of execute the :removeFromPath as part of the script! Copy and paste my entire example and try again... – Anders Sep 01 '17 at 13:36
  • @Anders Well I posted everything I have so far. If I use `%exampleRemoveDir%` The echo within `:removeFromPath` is not even issued. But I guess I am doing something wrong on a whole other level... -.- – Lilo Sep 01 '17 at 13:41
  • "if not defined %~1 exit /b 2" is never going to work, remove that line. You cannot check if a parameter does not exist, you can only check to see if it is empty. – Anders Sep 01 '17 at 13:56
  • @Anders Okay thanks, found in somewhere else here on Stackoverflow. :/ You're code is working fine now! :) But somehow `:isInPath` is always returning zero now. Don't know why that all of a sudden. :( You don't fortunately know why that is, do you? – Lilo Sep 01 '17 at 14:07
  • At the start of `:isInPath` you should do `set foundPathVar=0`, also `exit b/ 0` should be `exit /b 0` but I can't tell if that will fix it just by looking at it. When you have a problem, try breaking it into smaller parts and echo your way forward until you discover where the issue is... – Anders Sep 01 '17 at 15:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/153486/discussion-between-lilo-and-anders). – Lilo Sep 01 '17 at 15:14

1 Answers1

2

You need to use delayed expansion if you want to use another variable as part of the variable substitution. You also need to deal with the possibility that the path you want to remove is at the end of %path% and therefore not terminated by a ;.

@echo off

set removedir=d:\bar
set PATH=c:\foo;%removedir%;y:\baz&REM Set example %path%

echo Starting with %%PATH%% set to %PATH%

setlocal enableextensions enabledelayedexpansion
set _=!PATH:%removedir%;=!
if "%_%" == "%PATH%" set _=!PATH:;%removedir%=!
endlocal & set PATH=%_%

echo %%PATH%% is now %PATH%

and here as a helper function:

@echo off
goto start

:removeFromPath 
echo.Debug: Starting function with remove=%~1 and %%PATH%%=%PATH%
setlocal enableextensions enabledelayedexpansion
set removedir=%~1
set _=!PATH:%removedir%;=!
if "%_%" == "%PATH%" set _=!PATH:;%removedir%=!
endlocal & set PATH=%_%
echo.Debug: Ending function with %%PATH%%=%PATH%
goto :EOF


:start
set exampleremovedir=d:\bar
set PATH=c:\foo;%exampleremovedir%;y:\baz&REM Set example %path%

echo Starting with %%PATH%% set to %PATH%

call :removeFromPath %exampleremovedir%

echo %%PATH%% is now %PATH%
Anders
  • 97,548
  • 12
  • 110
  • 164
  • This works great as long as I don't scope it into a function. If I put function `:removeFromPath` where I do `set removedir=%~1` and then use your code even the echo inside that function shows an unchanged path. What am I missing here? – Lilo Sep 01 '17 at 12:54
  • @Lilo have you tried to `setlocal enabledelayedexpansion` inside the function? – Gerhard Sep 01 '17 at 13:04
  • @GerhardBarnard Yes, I did. I don't see much of difference but it won't work... :( – Lilo Sep 01 '17 at 13:13
  • @Anders something I noticed, if `exampleremovedir` is at the end of the path, it leaves a `;` at the end of the path – Gerhard Sep 01 '17 at 13:22
  • @GerhardBarnard: Thanks, should be fixed now – Anders Sep 01 '17 at 13:32