【问题标题】:How to convert absolute path to relative path in PowerShell?如何在PowerShell中将绝对路径转换为相对路径?
【发布时间】:2012-09-12 20:51:06
【问题描述】:

我想在 PowerShell 脚本中将路径转换为相对路径。 如何使用 PowerShell 执行此操作?

例如:

Path to convert: c:\documents\mynicefiles\afile.txt
Reference path:  c:\documents
Result:          mynicefiles\afile.txt

Path to convert: c:\documents\myproject1\afile.txt
Reference path:  c:\documents\myproject2
Result:          ..\myproject1\afile.txt

【问题讨论】:

    标签: powershell


    【解决方案1】:

    我发现了一些内置的东西,Resolve-Path:

    Resolve-Path -Relative
    

    这将返回相对于当前位置的路径。一个简单的用法:

    $root = "C:\Users\Dave\"
    $current = "C:\Users\Dave\Documents\"
    $tmp = Get-Location
    Set-Location $root
    Resolve-Path -relative $current
    Set-Location $tmp
    

    【讨论】:

    • 除了使用临时变量之外,您还可以使用 Push-Location 和 Pop-Location 设置位置,然后恢复为原始值。相同的基本解决方案,但没有临时变量。
    • 如果根目录还不存在,这将失败。
    • 聪明,但我不喜欢更改工作目录的副作用(即使您将其切换回来)
    • 为确保即使Resolve-Path 抛出异常(取决于$ErrorActionPreference)也能恢复当前位置,请将代码包装在try/catch 中:try{ push-location $root; resolve-path -relative $current } finally{ pop-location }
    【解决方案2】:

    使用内置的System.IO.Path.GetRelativePath 比接受的答案更简单:

    [System.IO.Path]::GetRelativePath($relativeTo, $path)
    

    【讨论】:

    • 我不同意“更安全”的说法,尽管它更简单。注意:这只适用于 .Net 5.0 RC 和 .Net core
    • 在 Windows 10 中,需要单独下载和安装 Powershell Core 才能支持这种 .Net Core 方法。接受的答案开箱即用。
    【解决方案3】:

    一种快速简便的方法是:

    $current -replace [regex]::Escape($root), '.'
    

    或者如果你想要从你的实际当前位置的相对路径

    $path -replace [regex]::Escape((pwd).Path), '.'
    

    这假设您的所有路径都是有效的。

    【讨论】:

    • 如果 $root 不是 $current 的根,则此方法不起作用(参见问题示例 2)
    【解决方案4】:

    here 有一个很好的答案,但它会更改您的当前目录(它会恢复),但如果您确实需要隔离该进程,下面的代码示例可以提供帮助。它做同样的事情,只是在一个新的 PowerShell 实例中。

    function Get-RelativePath($path, $relativeTo) {
        $powershell = (Get-Process -PID $PID | Get-Item)
        if ([string]::IsNullOrEmpty($powershell)) {
            $powershell = "powershell.exe"
        }
    
        & $powershell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "& { Set-Location `"$relativeTo`"; Resolve-Path `"$path`" -Relative}"
    }
    

    虽然它真的很慢,除非你绝对必须使用它,否则你真的应该使用其他版本。

    【讨论】:

      【解决方案5】:

      有时我有多个“根”,我想从中生成相对文件路径。我发现Resolve-Path -Relative 在这种情况下无法使用。更改全局设置、当前位置以生成相对文件路径似乎容易出错并且(如果您正在编写并行代码)可能不是线程安全的。

      以下内容应该适用于早期或最新版本的 Powershell 和 Powershell Core,不会更改您的当前目录,即使是暂时的,并且是独立于操作系统和线程安全的。

      它没有解决 OP 中的第二个示例(根据需要插入 ..。)

      function Get-RelativePath {
          param($path, $relativeTo)
          # strip trailing slash
          $relativeTo = Join-Path `
                            (Split-Path -Parent $relativeTo) `
                            (Split-Path -Leaf $relativeTo)
          $relPath = Split-Path -Leaf $path
          $path = Split-Path -Parent $path
          do {    
              $leaf = Split-Path -Leaf $path
              $relPath = Join-Path $leaf $relPath
              $path = Split-Path -Parent $path
          } until (($path -eq $relativeTo) -Or ($path.Length -eq 0))
          $relPath
      }
      

      一个例子:

      PS> $configRoot = 'C:\Users\P799634t\code\RMP\v2\AWD'
      PS> $queryPath = 'C:\Users\P799634t\code\RMP\v2\AWD\config_queries\LOAD_UNQ_QUEUE_QUERY2.sql'
      PS> Write-Host (Get-RelativePath $queryPath $configRoot)
      config_queries\LOAD_UNQ_QUEUE_QUERY2.sql
      

      当一个文件路径不是另一个文件的子路径时,它的行为是合理的:

      PS> $root = 'C:\Users\P799634t\code\RMP\v2\AWD'
      PS> $notRelated = 'E:\path\to\origami'
      PS> Write-Host (Get-RelativePath $notRelated $root)
      E:\path\to\origami
      

      【讨论】:

        【解决方案6】:

        这是另一种方法

        $pathToConvert1 = "c:\documents\mynicefiles\afile.txt"
        $referencePath1 = "c:\documents"
        $result1 = $pathToConvert1.Substring($referencePath1.Length + 1)
        #$result1:  mynicefiles\afile.txt
        


        还有

        $pathToConvert2 = "c:\documents\myproject1\afile.txt"
        #$referencePath2 = "c:\documents\myproject2"
        $result2 = "..\myproject" + [regex]::Replace($pathToConvert2 , ".*\d+", '')
        #$result2:          ..\myproject\afile.txt
        

        注意:在第二种情况下,没有使用参考路径。

        【讨论】:

        • 我想你误解了这两个例子。我想要一种方法来解决这两个问题。
        • 是的,我误解了你的例子,因为它指向文件绝对路径。
        • 不是 OP,但这是我要解决的问题。谢谢
        猜你喜欢
        • 2017-08-01
        • 2011-11-07
        • 2011-05-02
        • 2015-01-24
        相关资源
        最近更新 更多