web-dev-qa-db-ja.com

%PATH%にディレクトリが存在するかどうかを確認する方法は?

PATH環境変数にディレクトリがすでに存在するかどうかを確認するにはどうすればよいですか?ここから始まります。ただし、以下のコードで何とかできたのは、%PATH%の最初のディレクトリをエコーするだけです。これはFORループなので、%PATH%内のすべてのディレクトリを列挙すると思いますが、最初のディレクトリのみを取得します。

これを行うより良い方法はありますか? %PATH%変数で動作するfindまたはfindstrのようなものですか?既に存在する可能性のあるものを追加しないように、%PATH%のディレクトリのリストにディレクトリが存在するかどうかを確認したいだけです。

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

しばらくの間、バッチファイルのプログラミングは行っていませんが、

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

文字列が見つからない場合は0が、見つからない場合は1以上が表示されます。

編集:Panosのおかげで、大文字と小文字を区別しないフラグが追加されました。

37
Randy

パスに何かが存在するかどうかを確認する別の方法は、存在する場合に失敗しない無実の実行可能ファイルを実行し、結果を確認することです。例として、次のコードスニペットはmavenがパスにあるかどうかをチェックします。

mvn --help > NUL 2> NUL 
if errorlevel 1 goto mvnNotInPath

だから私はmvn --helpを実行しようとし、出力を無視します(mavenが存在する場合、実際にヘルプを見たくない)(> NUL) Mavenが見つからなかった場合、エラーメッセージを表示します(2> NUL)。

21
bert bruynooghe

ここで答えを読んだ後、私は新しい視点を提供できると思います:この質問の目的が知ることである場合特定の実行可能ファイルへのパス%PATH%そしてそうでなければ、それを挿入し(そしてこれが唯一の理由ですそれをするために、私は思う)、それはわずかに異なる方法で解決するかもしれない: "特定のディレクトリの確認方法実行可能プログラムは%PATH% "に存在しますか?この質問はこの方法で簡単に解決できます。

for %%p in (programname.exe) do set "progpath=%%~$PATH:p"
if not defined progpath (
   rem The path to programname.exe don't exist in PATH variable, insert it:
   set "PATH=%PATH%;C:\path\to\progranname"
)

実行可能ファイルの拡張子がわからない場合は、すべてを確認してください。

set "progpath="
for %%e in (%PATHEXT%) do (
   if not defined progpath (
      for %%p in (programname.%%e) do set "progpath=%%~$PATH:p"
   )
)
8
Aacini

for および delims を使用すると、任意の数のフィールドをキャプチャできません( Adam指摘 としてまあ)ので、代わりにループ技術を使用する必要があります。次のコマンドスクリプトは、PATH環境変数の各パスを個別の行にリストします。

@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

多くのプログラミング言語で見られる古典的なwhilewend構造をシミュレートします。これを適切に配置すると、 findstr のようなものを使用して、特定のパスを後でフィルタリングして検索できます。たとえば、上記のスクリプトをtidypath.cmdというファイルに保存した場合、次のようにfindstrにパイプして、標準プログラムディレクトリの下でパスを検索できます(大文字と小文字を区別しない一致を使用)。

> tidypath | findstr /i "%ProgramFiles%"
6
Atif Aziz

これにより、大文字と小文字を区別せずに完全に一致するものが検索されるため、末尾のバックスラッシュなどに注意してください。

for %P in ("%path:;=";"%") do @if /i %P=="PATH_TO_CHECK" echo %P exists in PATH

または、引数を取るバッチファイル(例:checkpath.bat):

@for %%P in ("%path:;=";"%") do @if /i %%P=="%~1" echo %%P exists in PATH

後者の形式では、たとえばcheckpath "%ProgramFiles%"指定されたパスが既にPATHに存在するかどうかを確認します。

この実装では、単一のパス項目内にセミコロンまたは引用符が存在しないことを前提としていることに注意してください。

4
mousio

forループを使用して実装を取得し、パスのすべての要素を反復処理するものに拡張しました。 forループの各反復は、パス全体(%qおよび%rに保持)からパスの最初の要素(%p)を削除します。

@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

サンプル出力:

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
2
indiv

あなたの質問が「なぜこのcmdスクリプトフラグメントが機能しないのか?」答えはfor /fが行を反復するということです。 delimsは行をフィールドに分割しますが、%%Pの最初のフィールドのみをキャプチャしています。 for /fループで任意の数のフィールドをキャプチャする方法はありません。

2
Adam Mitz

Heyvoon's(2015.06.08) Powershellを使用した応答について詳しく説明するために、この単純なPowershellスクリプトは%path%の詳細を提供します。

$env:Path -split ";" | % {"$(test-path $_);$_"}

独立して検証できるこの種の出力を生成する

True;C:\WINDOWS
True;C:\WINDOWS\system32
True;C:\WINDOWS\System32\Wbem
False;C:windows\System32\windowsPowerShell\v1.0\
False;C:\Program Files (x86)\Java\jre7\bin

パスを更新するために再構築するには:

$x=$null;foreach ($t in ($env:Path -split ";") ) {if (test-path $t) {$x+=$t+";"}};$x
2
Albert

サブストリング置換を使用して、サブストリングの存在をテストすることもできます。ここで、引用符を削除してPATH_NQを作成し、次にPATH_NQから「c:\ mydir」を削除し、元のものと比較して変更があったかどうかを確認します。

set PATH_NQ=%PATH:"=%
if not "%PATH_NQ%"=="%PATH_NQ:c:\mydir=%" goto already_in_path
set PATH=%PATH%;c:\mydir
:already_in_path
2
Kevin Edwards

ディレクトリがまだ存在しない場合、PATHに追加します。

set myPath=c:\mypath
For /F "Delims=" %%I In ('echo %PATH% ^| find /C /I "%myPath%"') Do set pathExists=%%I 2>Nul
If %pathExists%==0 (set PATH=%myPath%;%PATH%)
2
Noam Manos

上記の回答のいくつかを組み合わせて、特定のパスエントリが存在することを保証するためにexactly as givenできるだけ簡潔に、コマンドラインにジャンクエコーがないようにしました。

set myPath=<pathToEnsure | %1>
echo ;%PATH%; | find /C /I ";%myPath%;" >nul
if %ERRORLEVEL% NEQ 0 set PATH=%PATH%;%myPath%
2
Redsplinter

PowerShellを使用してこれを実現できます。

Test-Path $ENV:SystemRoot\YourDirectory
Test-Path C:\Windows\YourDirectory

これはTRUEまたはFALSEを返しました

短く、シンプルで簡単!

1
Heyvoon

Rcarの答えに基づいて、ターゲットのサブストリングが見つからないことを確認する必要があります。

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
1
Adam Mitz

代わりとして:

  1. PATH変数を検索するフォルダーに、コンピューター上の他のファイルが存在することは決してないような、通常とは異なる名前の一時ファイルを作成します。

  2. 環境変数(通常はPATH)で定義されたディレクトリリストを検索して、ファイルの検索を実行できる標準のバッチスクリプト構造を使用します。

  3. 検索結果が問題のパスと一致するかどうかを確認し、結果を表示します。

  4. 一時ファイルを削除します。

これは次のようになります。

@ECHO OFF
SET "mypath=D:\the\searched-for\path"
SET unusualname=nowthisissupposedtobesomeveryunusualfilename
ECHO.>"%mypath%\%unusualname%"
FOR %%f IN (%unusualname%) DO SET "foundpath=%%~dp$PATH:f"
ERASE "%mypath%\%unusualname%"
IF "%mypath%" == "%foundpath%" (
  ECHO The dir exists in PATH
) ELSE (
  ECHO The dir DOES NOT exist in PATH
)

既知の問題点:

  1. このメソッドは、ディレクトリが存在する場合にのみ機能します(常にそうであるとは限りません)。

  2. ディレクトリ内でファイルを作成/削除すると、その「変更された日付/時刻」属性に影響します(これは望ましくない結果になる場合があります)。

  3. 心の中でグローバルに一意のファイル名を作成することは、非常に信頼できるとは見なされません。そのような名前を生成すること自体は簡単な作業ではありません。

1
Andriy M

このバージョンはかなりうまく機能します。 vim71がパスにあるかどうかを確認し、ない場合は先頭に追加します。

@echo off
echo %PATH% | find /c /i "vim71" > nul
if not errorlevel 1 goto jump
PATH = C:\Program Files\Vim\vim71\;%PATH%
:jump

このデモは、エラーレベルロジックを説明するものです。

@echo on
echo %PATH% | find /c /i "Windows"
if "%errorlevel%"=="0" echo Found Windows
echo %PATH% | find /c /i "Nonesuch"
if "%errorlevel%"=="0" echo Found Nonesuch

Errorlevel 1はerrorlevel> = 1と同等であるため、vim71コードではロジックが逆になります。errorlevel0は常にtrueと評価されるため、 "not errorlevel 1" 使用されている。

Postscript setlocalおよびendlocalを使用して環境設定をローカライズする場合、チェックは必要ない場合があります。

@echo off
setlocal
PATH = C:\Program Files\Vim\vim71\;%PATH%
rem your code here
endlocal

エンドローカルの後、元のパスに戻ります。

1
Chris Degnen

これは、文字列置換を使用したKevin Edwardsの回答のバリエーションです。基本的なパターンは次のとおりです。

IF "%PATH:new_path=%" == "%PATH%" PATH=%PATH%;new_path

例えば:

IF "%PATH:C:\Scripts=%" == "%PATH%" PATH=%PATH%;C:\Scripts

簡単に言えば、PATH環境変数からnew_pathを削除/置換しようとする条件付きテストを作成します。 new_pathが存在しない場合、条件は成功し、new_pathPATHに初めて追加されます。 new_pathがすでに存在する場合、条件は失敗し、new_pathを再度追加しません。

1
Stephen Quan

「addPath」スクリプトへのコメント。パスにスペースを指定すると、スローされます。

例:addPath "c:\ Program Files(x86)\ Microsoft SDKs\Windows\v7.0A\Bin"を呼び出します

yields: 'Files'は、内部コマンドまたは外部コマンド、操作可能なプログラム、またはバッチファイルとして認識されません。

1
Morten Grøtan

ディレクトリが既に存在する場合、ディレクトリを検索パスに追加することを避けたいと言います。ディレクトリをパスに永続的に保存するつもりですか、それともバッチファイルのために一時的に保存するだけですか?

PATHにディレクトリを永続的に追加(または削除)したい場合は、管理タスクについてWindowsリソースキットツールのパスマネージャー(pathman.exe)ユーティリティを参照してください http://support.Microsoft.com/kb/927229 。これにより、システムパスとユーザーパスの両方のコンポーネントを追加または削除でき、重複エントリなどの異常を処理します。

バッチファイルのパスを一時的にのみ変更する必要がある場合は、パスの前に余分なパスを追加するだけです。パスのエントリが重複するため、パフォーマンスがわずかに低下するリスクがあります。

1
ketorin

一般に、これはパスにexe/dllを配置することです。このファイルが他の場所に表示されない限り:

@echo off
where /q <put filename here>    
if %errorlevel% == 1 (
    setx PATH "%PATH%;<additional path stuff>"
) else (
    echo "already set path"
)
1
user1454091

このルーチンは、パス変数でpath \またはfile.extを検索し、見つかった場合は0を返します。引用符で囲まれている場合、パスまたはファイルにスペースが含まれる場合があります。変数が最後の引数として渡される場合、d:\path\fileに設定されます。

@echo off&goto :PathCheck
:PathCheck.CMD
echo.PathCheck.CMD: Checks for existence of a path or file in %%PATH%% variable
echo.Usage: PathCheck.CMD [Checkpath] or [Checkfile] [PathVar]
echo.Checkpath must have a trailing \ but checkfile must not
echo.If Checkpath contains spaces use quotes ie. "C:\Check path\"
echo.Checkfile must not include a path, just the filename.ext
echo.If Checkfile contains spaces use quotes ie. "Check File.ext"
echo.Returns 0 if found, 1 if not or -1 if checkpath does not exist at all
echo.If PathVar is not in command line it will be echoed with surrounding quotes
echo.If PathVar is passed it will be set to d:\path\checkfile with no trailing \
echo.Then %%PathVar%% will be set to the fully qualified path to Checkfile
echo.Note: %%PathVar%% variable set will not be surrounded with quotes
echo.To view the path listing line by line use: PathCheck.CMD /L
exit/b 1

:PathCheck
if "%~1"=="" goto :PathCheck.CMD
setlocal EnableDelayedExpansion
set "PathVar=%~2"
set "pth="
set "pcheck=%~1"
if "%pcheck:~-1%" equ "\" (
  if not exist %pcheck% endlocal&exit/b -1
  set/a pth=1
) 
for %%G in ("%path:;=" "%") do (
  set "Pathfd=%%~G\"
  set "Pathfd=!Pathfd:\\=\!"
  if /i "%pcheck%" equ "/L" echo.!Pathfd!
  if defined pth (
    if /i "%pcheck%" equ "!Pathfd!" endlocal&exit/b 0
  ) else (
    if exist "!Pathfd!%pcheck%" goto :CheckfileFound
  )
)
endlocal&exit/b 1

:CheckfileFound
endlocal&(
  if not "%PathVar%"=="" (
    call set "%~2=%Pathfd%%pcheck%"
  ) else (echo."%Pathfd%%pcheck%")
  exit/b 0
)
0
carlsomo

-contains私のために働いた

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

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

まだ存在しないパスを追加するには

$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
}
0