How to check if a directory exists in %PATH%

Viewed 157545

How does one check if a directory is already present in the PATH environment variable? Here's a start. All I've managed to do with the code below, though, is echo the first directory in %PATH%. Since this is a FOR loop you'd think it would enumerate all the directories in %PATH%, but it only gets the first one.

Is there a better way of doing this? Something like FIND or FINDSTR operating on the %PATH% variable? I'd just like to check if a directory exists in the list of directories in %PATH%, to avoid adding something that might already be there.

FOR /F "delims=;" %%P IN ("%PATH%") DO (
    @ECHO %%~P
)
22 Answers

This may work:

echo ;%PATH%; | find /C /I ";<string>;"

It should give you 0 if the string is not found and 1 or more if it is.

Using for and delims, you cannot capture an arbitrary number of fields (as Adam pointed out as well) so you have to use a looping technique instead. The following command script will list each path in the PATH environment variable on a separate line:

@echo off 
setlocal 
if "%~1"=="" (
    set PATHQ=%PATH%
) else (
    set PATHQ=%~1 ) 
:WHILE
    if "%PATHQ%"=="" goto WEND
    for /F "delims=;" %%i in ("%PATHQ%") do echo %%i
    for /F "delims=; tokens=1,*" %%i in ("%PATHQ%") do set PATHQ=%%j
    goto WHILE 
:WEND

It simulates a classical whilewend construct found in many programming languages. With this in place, you can use something like findstr to subsequently filter and look for a particular path. For example, if you saved the above script in a file called tidypath.cmd then here is how you could pipe to findstr, looking for paths under the standard programs directory (using a case-insensitive match):

> tidypath | findstr /i "%ProgramFiles%"

If your question was "why doesn't this cmd script fragment work?" then the answer is that for /f iterates over lines. The delims split lines into fields, but you're only capturing the first field in %%P. There is no way to capture an arbitrary number of fields with a for /f loop.

I took your implementation using the for loop and extended it into something that iterates through all elements of the path. Each iteration of the for loop removes the first element of the path (%p) from the entire path (held in %q and %r).

@echo off
SET MYPATHCOPY=%PATH%

:search
for /f "delims=; tokens=1,2*" %%p in ("%MYPATHCOPY%") do (
   @echo %%~p
   SET MYPATHCOPY=%%~q;%%~r
)

if "%MYPATHCOPY%"==";" goto done;
goto search;

:done

Sample output:

Z:\>path.bat
C:\Program Files\Microsoft DirectX SDK (November 2007)\Utilities\Bin\x86
c:\program files\imagemagick-6.3.4-q16
C:\WINDOWS\system32
C:\WINDOWS
C:\SFU\common\
c:\Program Files\Debugging Tools for Windows
C:\Program Files\Nmap

Building on Randy's answer, you have to make sure a substring of the target isn't found.

if a%X%==a%PATH% echo %X% is in PATH
echo %PATH% | find /c /i ";%X%"
if errorlevel 1 echo %X% is in PATH
echo %PATH% | find /c /i "%X%;"
if errorlevel 1 echo %X% is in PATH

You mention that you want to avoid adding the directory to search path if it already exists there. Is your intention to store the directory permanently to the path, or just temporarily for batch file's sake?

If you wish to add (or remove) directories permanently to PATH, take a look at Path Manager (pathman.exe) utility in Windows Resource Kit Tools for administrative tasks, http://support.microsoft.com/kb/927229. With that you can add or remove components of both system and user paths, and it will handle anomalies such as duplicate entries.

If you need to modify the path only temporarily for a batch file, I would just add the extra path in front of the path, with the risk of slight performance hit because of duplicate entry in the path.

-contains worked for me

$pathToCheck = "c:\some path\to\a\file.txt"

$env:Path - split ';' -contains $pathToCheck

To add the path when it does not exist yet I use

$pathToCheck = "c:\some path\to\a\file.txt"

if(!($env:Path -split ';' -contains $vboxPath)) {
  $documentsDir = [Environment]::GetFolderPath("MyDocuments")
  $profileFilePath = Join-Path $documentsDir "WindowsPowerShell/profile.ps1"
  Out-File -FilePath $profileFilePath -Append -Force -Encoding ascii -InputObject "`$env:Path += `";$pathToCheck`""
  Invoke-Expression -command $profileFilePath
}
rem https://stackoverflow.com/a/59571160/2292993
rem Don't get mess with %PATH%, it is a concatenation of USER+SYSTEM, and will cause a lot of duplication in the result. 
for /f "usebackq tokens=2,*" %%A in (`reg query HKCU\Environment /v PATH`) do set userPATH=%%B
rem userPATH should be %USERPROFILE%\AppData\Local\Microsoft\WindowsApps

rem https://stackoverflow.com/questions/141344
for /f "delims=" %%A in ('echo ";%userPATH%;" ^| find /C /I ";%WINAPPS%;"') do set pathExists=%%A
If %pathExists%==0 (
    echo Inserting user path...
    setx PATH "%WINAPPS%; %userPATH%"
)
Related