Как проверить, находится ли файл в указанном каталоге в PowerShell? - PullRequest
6 голосов
/ 23 июня 2009

Я хочу проверить, находится ли путь к файлу в заданном каталоге (или в одном из его подкаталогов) из PowerShell.

Прямо сейчас я делаю:

$file.StartsWith(  $directory, [StringComparison]::InvariantCultureIgnoreCase )

но я уверен, что есть лучшие способы.

Я мог бы взять $file.Directory и повторить все .Parent с, но я надеялся на что-то более простое.

РЕДАКТИРОВАТЬ : файл может не существовать; Я просто смотрю на путь.

Ответы [ 5 ]

6 голосов
/ 23 июня 2009

Как насчет чего-то простого:

PS> gci . -r foo.txt

Это неявно использует параметр -filter (по позиции), определяющий foo.txt в качестве фильтра. Вы также можете указать * .txt или foo? .Txt. Проблема с StartsWith заключается в том, что, хотя вы обрабатываете сравнение без учета регистра, все равно остается проблема, что оба / и \ являются допустимыми разделителями пути в PowerShell.

Предполагая, что файл может не существовать, а $ file и $ directory являются абсолютными путями, вы можете сделать это "PowerShell" следующим образом:

(Split-Path $file -Parent) -replace '/','\' -eq (Get-Item $directory).FullName

Но это не очень хорошо, так как вам все еще нужно канонизировать путь / -> \, но по крайней мере сравнение строк в PowerShell не учитывает регистр. Другой вариант - использовать IO.Path для канонизации пути, например ::10000

[io.path]::GetDirectoryName($file) -eq [io.path]::GetFullPath($directory)

Одна проблема, связанная с этим, заключается в том, что GetFullPath также сделает относительный путь абсолютным путем, основанным на текущем каталоге процесса, который чаще всего не совпадает с текущим каталогом PowerShell. Так что просто убедитесь, что $ directory является абсолютным путем, даже если вы должны указать его как "$ pwd \ $ directory".

1 голос
/ 14 ноября 2009

Поскольку путь может не существовать, использование string.StartsWith хорошо для выполнения этого типа теста (хотя OrdinalIgnoreCase является лучшим представлением того, как файловая система сравнивает пути ).

Единственное предостережение в том, что дорожки должны быть в канонической форме. В противном случае пути типа C:\x\..\a\b.txt и C:/a/b.txt не пройдут тест «это под каталогом C:\a\». Вы можете использовать статический метод Path.GetFullPath, чтобы получить полные имена путей перед выполнением теста:

function Test-SubPath( [string]$directory, [string]$subpath ) {
  $dPath = [IO.Path]::GetFullPath( $directory )
  $sPath = [IO.Path]::GetFullPath( $subpath )
  return $sPath.StartsWith( $dPath, [StringComparison]::OrdinalIgnoreCase )
}

Также обратите внимание, что это не распространяется на логическое сдерживание (например, если у вас \\some\network\path\ сопоставлено с Z:\path\, проверка того, находится ли \\some\network\path\b.txt ниже Z:\, будет неудачной, даже если файл доступен через Z:\path\b.txt ). Если вам нужно поддержать это поведение, эти вопросы могут помочь.

0 голосов
/ 31 марта 2014

Если вы преобразуете свои входные строки в DirectoryInfo и FileInfo, у вас не возникнет проблем со сравнением строк.

function Test-FileInSubPath([System.IO.DirectoryInfo]$Dir,[System.IO.FileInfo]$File)
{
    $File.FullName.StartsWith($Dir.FullName)
}
0 голосов
/ 23 июня 2009

Как то так?

Get-ChildItem -Recurse $directory | Where-Object { $_.PSIsContainer -and `
    $_.FullName -match "^$($file.Parent)" } | Select-Object -First 1
0 голосов
/ 23 июня 2009

Что-то очень быстрое:

14:47:28 PS>pwd

C:\Documents and Settings\me\Desktop

14:47:30 PS>$path = pwd

14:48:03 PS>$path

C:\Documents and Settings\me\Desktop

14:48:16 PS>$files = Get-ChildItem $path -recurse | 
                     Where {$_.Name -match "thisfiledoesnt.exist"}

14:50:55 PS>if ($files) {write-host "the file exists in this path somewhere"
            } else {write-host "no it doesn't"}
no it doesn't

(создайте новый файл на рабочем столе или в папке на рабочем столе и назовите его "thisfileexists.txt")

14:51:03 PS>$files = Get-ChildItem $path -recurse | 
                     Where {$_.Name -match "thisfileexists.txt"}

14:52:07 PS>if($files) {write-host "the file exists in this path somewhere"
            } else {write-host "no it doesn't"}
the file exists in this path somewhere

Конечно, итерации все еще происходят, но PS делает это для вас. Вам также может понадобиться -force, если вы ищете системные / скрытые файлы.

...