如何在PowerShell中规范化路径?

dan*_*gph 85 powershell path

我有两条路:

fred\frog
Run Code Online (Sandbox Code Playgroud)

..\frag
Run Code Online (Sandbox Code Playgroud)

我可以在PowerShell中将它们连接在一起,如下所示:

join-path 'fred\frog' '..\frag'
Run Code Online (Sandbox Code Playgroud)

这给了我这个:

fred\frog\..\frag
Run Code Online (Sandbox Code Playgroud)

但我不希望这样.我想要一个没有双点的标准化路径,如下所示:

fred\frag
Run Code Online (Sandbox Code Playgroud)

我怎么能得到它?

Sha*_*evy 99

您可以使用resolve-path将..\frag扩展为其完整路径:

PS > resolve-path ..\frag 
Run Code Online (Sandbox Code Playgroud)

尝试使用combine()方法规范化路径:

[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
Run Code Online (Sandbox Code Playgroud)

  • Resolve-Path仅在路径存在时有效. (25认同)
  • `[io.path]::Combine` 的参数是相反的。更好的是,使用原生的 `Join-Path` PowerShell 命令:`Join-Path (Resolve-Path ..\frag).Path 'fred\frog'` 还要注意,至少从 PowerShell v3 开始,`Resolve-Path ` 现在支持 `-Relative` 开关来解析相对于当前文件夹的路径。如前所述,“Resolve-Path”仅适用于现有路径,与“[IO.Path]::GetFullPath()”不同。 (3认同)

Joh*_*ren 77

您可以使用组合pwd,Join-Path[System.IO.Path]::GetFullPath获得完全限定的扩展路径.

由于cd(Set-Location)不会更改进程当前工作目录,只需将相对文件名传递给不能理解PowerShell上下文的.NET API,就会产生意想不到的副作用,例如根据初始工作解析路径目录(不是您当前的位置).

你做的是你首先确定你的道路:

Join-Path (Join-Path (pwd) fred\frog) '..\frag'
Run Code Online (Sandbox Code Playgroud)

这会产生(给定我当前的位置):

C:\WINDOWS\system32\fred\frog\..\frag
Run Code Online (Sandbox Code Playgroud)

使用绝对库,可以安全地调用.NET API GetFullPath:

[System.IO.Path]::GetFullPath((Join-Path (Join-Path (pwd) fred\frog) '..\frag'))
Run Code Online (Sandbox Code Playgroud)

这为您提供了完全限定的路径并..删除了:

C:\WINDOWS\system32\fred\frag
Run Code Online (Sandbox Code Playgroud)

它也不复杂,我个人不屑依赖于这个外部脚本的解决方案,这是要解决相当贴切简单的问题,Join-Pathpwd(GetFullPath只是让它漂亮).如果你只想保留相关部分,你只需添加.Substring((pwd).Path.Trim('\').Length + 1)并瞧!

fred\frag
Run Code Online (Sandbox Code Playgroud)

UPDATE

感谢@Dangph指出C:\边缘情况.

  • 或者,只需使用:$ ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath(“。\ nonexist \ foo.txt”)也可以用于不存在的路径。“ x0n”值得称赞。正如他指出的那样,它解析为PSPath,而不是flilesystem路径,但是,如果您使用PowerShell中的路径,谁在乎呢?http://stackoverflow.com/questions/3038337/powershell-resolve-path-that-might-not-exist (2认同)

Cha*_*lie 25

您也可以使用Path.GetFullPath,尽管(与Dan R的答案一样),这将为您提供整个路径.用法如下:

[IO.Path]::GetFullPath( "fred\frog\..\frag" )
Run Code Online (Sandbox Code Playgroud)

或者更有趣的是

[IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") )
Run Code Online (Sandbox Code Playgroud)

两者都产生以下结果(假设您当前的目录是D:\):

D:\fred\frag
Run Code Online (Sandbox Code Playgroud)

请注意,此方法不会尝试确定fred或frag是否实际存在.

  • 您的问题是您需要在.NET中设置当前目录.`[System.IO.Directory] ​​:: SetCurrentDirectory(((Get-Location -PSProvider FileSystem).ProviderPath))` (8认同)
  • 只是明确说明:`[IO.Path] :: GetFullPath()`,与PowerShell的原生`Resolve-Path`不同,也适用于不存在的路径.它的缺点是需要首先将.NET的工作文件夹与PS同步,正如@JasonMArcher所指出的那样. (2认同)

小智 18

接受的答案是一个很大的帮助,但它也没有正确地"正常化"绝对路径.在下面找到我的衍生作品,它规范了绝对和相对路径.

function Get-AbsolutePath ($Path)
{
    # System.IO.Path.Combine has two properties making it necesarry here:
    #   1) correctly deals with situations where $Path (the second term) is an absolute path
    #   2) correctly deals with situations where $Path (the second term) is relative
    # (join-path) commandlet does not have this first property
    $Path = [System.IO.Path]::Combine( ((pwd).Path), ($Path) );

    # this piece strips out any relative path modifiers like '..' and '.'
    $Path = [System.IO.Path]::GetFullPath($Path);

    return $Path;
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*ome 10

任何非PowerShell路径操作函数(例如System.IO.Path中的函数)都不可靠来自PowerShell,因为PowerShell的提供程序模型允许PowerShell的当前路径与Windows认为该进程的工作目录不同.

此外,正如您可能已经发现的那样,PowerShell的Resolve-Path和Convert-Path cmdlet对于将相对路径(包含'..'的路径)转换为驱动限定的绝对路径非常有用,但如果引用的路径不存在则它们会失败.

以下非常简单的cmdlet应适用于不存在的路径.它会将'fred\frog\..\frag'转换为'd:\ fred\frag',即使找不到'fred'或'frag'文件或文件夹(并且当前的PowerShell驱动器是'd:') .

function Get-AbsolutePath {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string[]]
        $Path
    )

    process {
        $Path | ForEach-Object {
            $PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($_)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于驱动器号不存在的不存在的路径,例如我没有Q:驱动器.`Get-AbsolutePath q:\ foo\bar\..\baz`即使是有效路径也会失败.好吧,取决于你对有效路径的定义.:-) FWIW,即使是内置的`Test-Path <path> -IsValid`也会在以不存在的驱动器为根的路径上失败. (2认同)
  • @KeithHill 换句话说,PowerShell 认为不存在的根上的路径无效。我认为这是相当合理的,因为 PowerShell 使用 root 来决定在使用它时使用哪种类型的提供程序。例如,`HKLM:\SOFTWARE` 是 PowerShell 中的有效路径,指的是本地计算机注册表配置单元中的 `SOFTWARE` 键。但是要确定它是否有效,它需要弄清楚注册表路径的规则是什么。 (2认同)

Wil*_*Cau 7

如果路径包含限定符(驱动器号),则x0n 对 Powershell 的回答:解析可能不存在的路径?将规范化路径。如果路径不包含限定符,它仍然会被规范化,但会返回相对于当前目录的完全限定路径,这可能不是您想要的。

$p = 'X:\fred\frog\..\frag'
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p)
X:\fred\frag

$p = '\fred\frog\..\frag'
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p)
C:\fred\frag

$p = 'fred\frog\..\frag'
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($p)
C:\Users\WileCau\fred\frag
Run Code Online (Sandbox Code Playgroud)