PowerShell如何处理“。”在路径上?

时间:2019-09-03 17:24:28

标签: windows powershell

打开PowerShell终端时,请考虑以下命令序列:

PS C:\Users\username> cd source
PS C:\Users\username\source> $dir = ".\temp"
PS C:\Users\username\source> [System.IO.Path]::GetFullPath($dir)
C:\Users\username\temp

现在,这个:

PS C:\Users\username> cd source
PS C:\Users\username\source> powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

Try the new cross-platform PowerShell https://aka.ms/pscore6

PS C:\Users\username\source> $dir = ".\temp"
PS C:\Users\username\source> [System.IO.Path]::GetFullPath($dir)
C:\Users\username\source\temp

PowerShell为什么解释“。”相对于启动PowerShell的目录,而不是当前目录?我怎样才能解释“。”相对于当前目录?

3 个答案:

答案 0 :(得分:3)

答案 1 :(得分:1)

正如js2010's helpful answer所述, .em方法的用法会引入问题
.NET的单个,整个进程范围的当前目录,通常是设计使然,它们是从PowerShell的 runspace特定的 [1] 不同 / em>一个。

这具有以下含义:

  • 因为 PowerShell本身确实能够可靠地将.解释为当前位置 (这是PowerShell对概念的概括)在其他PowerShell驱动器提供程序(例如 registry 提供程序)公开的驱动器上的当前目录也可以引用其他类型的位置,您可以通过使用 PowerShell 命令(如果可用)来避免此问题。

  • 当您调用.NET方法时,请确保预先解析绝对路径的所有相对路径 ,或者在支持的情况下,另外提供当前的PowerShell文件系统位置作为 reference 目录-避免了当前目录不匹配的问题。

    • (另一个但次优的选择是每次通过相对路径时首先设置[Environment]::CurrentDirectory = $PWD.ProviderPath,但这很笨拙,如果同一进程中可能存在多个PowerShell运行空间,则不应使用。 )

下一部分显示如何安全地将相对PowerShell路径传递给.NET方法,而下部分解决了您的问题中的特定问题:如何将给定的PowerShell路径解析为绝对的本机文件系统路径。


将已知的相对PowerShell路径安全地传递到.NET方法:

如上所述,当前目录中的差异要求将绝对路径传递给.NET方法,该路径基于 PowerShell 的当前目录到达。

这些示例假定相对路径someFile.txt将传递给.NET方法[IO.File]::ReadAllText()

请注意,使用简单的字符串插值,使用/(可以与\互换使用)来连接路径组件;如果当前目录恰好是 root 目录,那么您将得到 2 路径分隔符,但这不会影响功能。但是,如果仍然需要避免这种情况,请改用Join-Path cmdlet。

    通过$PWD
  • 简单但不完全健壮(如果当前目录基于使用{{1}创建的 PowerShell专用驱动器,则失败},或者当前位置不是文件系统位置):
New-PsDrive
  • 更强大:通过[IO.File]::ReadAllText("$PWD/someFile.txt") (将基于PowerShell驱动器的路径解析为基础本机文件系统路径,但是如果当前位置不是文件系统< / em>位置):
$PWD.ProviderPath
  • 完全可靠:通过[IO.File]::ReadAllText("$($PWD.ProviderPath)/someFile.txt")
(Get-Location -PSProvider FileSystem).ProviderPath

注意:上面的方法适用于存在和不存在的路径; 如果已知存在该路径(例如使用[IO.File]::ReadAllText("$((Get-Location -PSProvider FileSystem).ProviderPath)/someFile.txt") ,而不是[IO.File]::ReadAllText()),则也可以使用以下内容,但前提是您可以进一步假设当前路径是location是一个文件系统位置:

[IO.File]::WriteAllText()

不幸的是,[IO.File]::ReadAllText((Convert-Path -LiteralPath someFile.txt)) Convert-Path仅适用于现有路径(自PowerShell Core 7.0.0-preview.3起); proposed on GitHub为不存在的路径提供了选择加入。

类似地,如果Resolve-Path已支持Convert-PathResolve-Path支持-PSProvider参数以允许显式指定目标提供者,则将很有帮助-请参见{{3 }}。


将给定的任意PowerShell文件系统路径解析为绝对本机路径:

如果路径存在,请使用Get-Location 将任何PowerShell文件系统路径解析为绝对的文件系统本机路径:

Convert-Path

相关的$dir = "./temp" Convert-Path -LiteralPath $dir cmdlet提供了类似的功能,但是它不会将基于 PowerShell特定驱动器(由Resolve-Path创建)的路径解析为其基础本机文件系统路径

如果路径不存在(还)

在基于.NET Core的PowerShell Core 中,您可以使用新的 New-PsDrive 重载接受参考目录 作为指定的相对路径:

[IO.Path]::GetFullPath()

请注意如何将当前位置的本机文件系统路径$dir = "./temp" [IO.Path]::GetFullPath($dir, $PWD.ProviderPath) 作为参考目录传递。

注意事项:如果当前位置可能位于文件系统驱动器之外的其他驱动器 上,请使用
$PWD.ProviderPath可靠地进行引用到当前的文件系统位置(目录)。

Windows PowerShell 中,您可以使用(Get-Location -PSProvider FileSystem).ProviderPath ,但是请注意,您必须删除{{1 }}如果您不希望在结果路径中添加前缀,

[IO.Path]::Combine()

[1]尽管一个给定的进程通常只有一个一个 PowerShell运行空间(会话),但是在一个进程中可能存在多个多个的可能性。从概念上讲,所有这些用户都无法将其单独的工作目录与一个且仅是整个进程范围内的.NET工作目录同步。有关更深入的说明,请参见this suggestion on GitHub

答案 2 :(得分:0)

Powershell将.视为当前位置。因此,如果您执行Get-ChildItem -Path ".\",这将返回当前目录中的所有内容。要获得相对路径,您需要执行以下操作:

Set-Location -Path "Path"
$path = Get-Item -Path "file" | Resolve-Path -Relative

$path现在将是相对路径