我想从 PowerShell 检查文件路径是否在给定目录(或其子目录之一)中。
现在我正在做:
$file.StartsWith( $directory, [StringComparison]::InvariantCultureIgnoreCase )
但我相信有更好的方法。
我可以接受$file.Directory
并遍历所有.Parent
s,但我希望有更简单的东西。
编辑:文件可能不存在;我只是在看路。
我想从 PowerShell 检查文件路径是否在给定目录(或其子目录之一)中。
现在我正在做:
$file.StartsWith( $directory, [StringComparison]::InvariantCultureIgnoreCase )
但我相信有更好的方法。
我可以接受$file.Directory
并遍历所有.Parent
s,但我希望有更简单的东西。
编辑:文件可能不存在;我只是在看路。
像这样简单的事情怎么样:
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 来规范化路径,例如:
[io.path]::GetDirectoryName($file) -eq [io.path]::GetFullPath($directory)
一个问题是,GetFullPath 还会根据进程的当前目录将相对路径设为绝对路径,这与PowerShell 的当前目录不同。所以只要确保 $directory 是一个绝对路径,即使您必须像“$pwd\$directory”一样指定它。
由于路径可能不存在,因此 usingstring.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
Something real quick:
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
(create new file on desktop or in a folder on the desktop and name it "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
Of course iterating is still happening, but PS is doing it for you. You also might need -force if looking for system/hidden files.
像这样的东西?
Get-ChildItem -Recurse $directory | Where-Object { $_.PSIsContainer -and `
$_.FullName -match "^$($file.Parent)" } | Select-Object -First 1
如果将输入字符串转换为 DirectoryInfo 和 FileInfo,则字符串比较不会有任何问题。
function Test-FileInSubPath([System.IO.DirectoryInfo]$Dir,[System.IO.FileInfo]$File)
{
$File.FullName.StartsWith($Dir.FullName)
}