41

我想将路径转换为 ​​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
4

6 回答 6

67

我发现了一些内置的东西,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
于 2012-09-12T21:13:36.510 回答
9

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

[System.IO.Path]::GetRelativePath($relativeTo, $path)
于 2020-10-26T15:54:35.447 回答
0

一种快速简便的方法是:

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

或者,如果您想要来自实际当前位置的相对路径

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

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

于 2018-09-06T15:01:23.413 回答
0

这里有一个很好的答案,但是它会更改您的当前目录(它会恢复),但是如果您确实需要隔离该进程,下面的代码示例可以提供帮助。它做同样的事情,只是在一个新的 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}"
}

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

于 2020-09-19T00:21:30.573 回答
0

有时我有多个“根”,我想从中生成相对文件路径。我发现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
于 2020-11-17T06:39:51.153 回答
-4

这是另一种方法

$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

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

于 2015-10-22T22:47:59.803 回答