如何在 PowerShell 中检查文件是否位于给定目录下?

发布于 2024-07-24 13:05:36 字数 327 浏览 3 评论 0原文

我想从 PowerShell 检查文件路径是否位于给定目录(或其子目录之一)中。

现在我正在做:

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

但我确信有更好的方法。

我可以采取 $file.Directory 并迭代所有 .Parent ,但我希望有更简单的东西。

编辑:该文件可能不存在; 我只是看着路。

I want to check if a file path is in a given directory (or one of its subdirectories), from PowerShell.

Right now I'm doing:

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

but I'm sure there are better ways.

I could do take $file.Directory and iterate over all .Parents, but I was hoping for something simpler.

EDIT: the file may not exist; I'm just looking at the path.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

初心未许 2024-07-31 13:05:36

像这样简单的事情怎么样:

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”那样指定它。

How about something as simple as:

PS> gci . -r foo.txt

This implicitly uses the -filter parameter (by position) specifying foo.txt as the filter. You could also specify *.txt or foo?.txt. The problem with StartsWith is that while you handle the case-insensitive compare there is still the issue that both / and \ are valid path separators in PowerShell.

Assuming the file may not exist and both $file and $directory are absolute paths, you can do this the "PowerShell" way:

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

But that isn't great since you still have to canonical the path / -> \ but at least the PowerShell string compare is case-insensitive. Another option is to use IO.Path to canonicalize the path e.g.:

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

One issue with this is that GetFullPath will also make a relative path an absolute path based on the process's current dir which more times than not, is not the same as PowerShell's current dir. So just make sure $directory is an absolute path even if you have to specify it like "$pwd\$directory".

睡美人的小仙女 2024-07-31 13:05:36

由于路径可能不存在,因此使用 string.StartsWith 可以很好地进行此类测试(尽管 OrdinalIgnoreCase 更好地表示了文件系统如何比较路径)。

唯一需要注意的是路径必须采用规范形式。 否则,像 C:\x\..\a\b.txtC:/a/b.txt 这样的路径将无法显示“is this under the ” >C:\a\ 目录”测试。 您可以使用静态 Path.GetFullPath< /code>方法在进行测试之前获取路径的全名:

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 访问该文件)。 如果您需要支持此行为,这些问题可能会有所帮助。

Since the path might not exist, using string.StartsWith is fine for doing this type of test (though OrdinalIgnoreCase is a better representation of how the file system compares paths).

The only caveat is that the paths need to be in a canonical form. Otherwise, paths like C:\x\..\a\b.txt and C:/a/b.txt would fail the "is this under the C:\a\ directory" test. You can use the static Path.GetFullPath method to get the full names of the paths before you do the test:

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

Also note that this does not cover logical containment (e.g. if you have \\some\network\path\ mapped to Z:\path\, testing whether \\some\network\path\b.txt is under Z:\ will fail, even though the file can be accessed through Z:\path\b.txt). If you need to support this behavior, these questions might help.

俯瞰星空 2024-07-31 13:05:36

如果将输入字符串转换为 DirectoryInfo 和 FileInfo,则字符串比较不会有任何问题。

function Test-FileInSubPath([System.IO.DirectoryInfo]$Dir,[System.IO.FileInfo]$File)
{
    $File.FullName.StartsWith($Dir.FullName)
}

If you convert your input strings to DirectoryInfo and FileInfo, you won't have any problem with the string comparison.

function Test-FileInSubPath([System.IO.DirectoryInfo]$Dir,[System.IO.FileInfo]$File)
{
    $File.FullName.StartsWith($Dir.FullName)
}
也只是曾经 2024-07-31 13:05:36

像这样的东西吗?

Get-ChildItem -Recurse $directory | Where-Object { $_.PSIsContainer -and `
    $_.FullName -match "^$($file.Parent)" } | Select-Object -First 1

Something like this?

Get-ChildItem -Recurse $directory | Where-Object { $_.PSIsContainer -and `
    $_.FullName -match "^$($file.Parent)" } | Select-Object -First 1
诗酒趁年少 2024-07-31 13:05:36

非常快的事情:(

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。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文