我有两条路:
fred\frog
和
..\frag
我可以像这样在 PowerShell 中将它们连接在一起:
join-path 'fred\frog' '..\frag'
这给了我这个:
fred\frog\..\frag
但我不想那样。我想要一个没有双点的标准化路径,如下所示:
fred\frag
我怎么能得到那个?
我有两条路:
fred\frog
和
..\frag
我可以像这样在 PowerShell 中将它们连接在一起:
join-path 'fred\frog' '..\frag'
这给了我这个:
fred\frog\..\frag
但我不想那样。我想要一个没有双点的标准化路径,如下所示:
fred\frag
我怎么能得到那个?
您可以使用 resolve-path 将 ..\frag 扩展到其完整路径:
PS > resolve-path ..\frag
尝试使用 combine() 方法规范化路径:
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
您可以使用$pwd
,Join-Path
和的组合[System.IO.Path]::GetFullPath
来获得完全限定的扩展路径。
由于cd
( Set-Location
) 不会更改进程的当前工作目录,因此只需将相对文件名传递给不理解 PowerShell 上下文的 .NET API,可能会产生意想不到的副作用,例如解析为基于初始工作的路径目录(不是您当前的位置)。
你要做的是首先限定你的路径:
Join-Path (Join-Path $pwd fred\frog) '..\frag'
这产生(给定我当前的位置):
C:\WINDOWS\system32\fred\frog\..\frag
有了绝对基础,现在可以安全地调用 .NET API GetFullPath
:
[System.IO.Path]::GetFullPath((Join-Path (Join-Path $pwd fred\frog) '..\frag'))
这为您提供了完全合格的路径,并..
正确解析:
C:\WINDOWS\system32\fred\frag
就个人而言,这也不复杂,我不屑于为此依赖外部脚本的解决方案,这是一个简单的问题,而通过Join-Path
and $pwd
(GetFullPath
只是为了让它漂亮) 解决了这个问题。如果您只想保留相关部分,您只需添加.Substring($pwd.Path.Trim('\').Length + 1)
并瞧!
fred\frag
感谢@Dangph 指出了极端C:\
情况。
您也可以使用Path.GetFullPath,尽管(与 Dan R 的回答一样)这将为您提供整个路径。用法如下:
[IO.Path]::GetFullPath( "fred\frog\..\frag" )
或者更有趣的是
[IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") )
两者都会产生以下结果(假设您的当前目录是 D:\):
D:\fred\frag
请注意,此方法不会尝试确定 fred 或 frag 是否实际存在。
接受的答案是一个很大的帮助,但是它也不能正确地“规范化”绝对路径。在下面找到我的衍生作品,它标准化了绝对和相对路径。
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;
}
任何非 PowerShell 路径操作函数(例如 System.IO.Path 中的那些)在 PowerShell 中都不可靠,因为 PowerShell 的提供程序模型允许 PowerShell 的当前路径与 Windows 认为的进程工作目录不同。
此外,您可能已经发现,PowerShell 的 Resolve-Path 和 Convert-Path cmdlet 对于将相对路径(包含 '..' 的那些)转换为驱动器限定的绝对路径很有用,但如果引用的路径不存在,它们会失败。
以下非常简单的 cmdlet 应该适用于不存在的路径。即使找不到“fred”或“frag”文件或文件夹(并且当前的 PowerShell 驱动器为“d:”),它也会将“fred\frog\..\frag”转换为“d:\fred\frag” .
function Get-AbsolutePath {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[string[]]
$Path
)
process {
$Path | ForEach-Object {
$PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($_)
}
}
}
如果路径包含限定符(驱动器号),那么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
这个库很好:NDepend.Helpers.FileDirectoryPath。
编辑:这就是我想出的:
[Reflection.Assembly]::LoadFrom("path\to\NDepend.Helpers.FileDirectoryPath.dll") | out-null
Function NormalizePath ($path)
{
if (-not $path.StartsWith('.\')) # FilePathRelative requires relative paths to begin with '.'
{
$path = ".\$path"
}
if ($path -eq '.\.') # FilePathRelative can't deal with this case
{
$result = '.'
}
else
{
$relPath = New-Object NDepend.Helpers.FileDirectoryPath.FilePathRelative($path)
$result = $relPath.Path
}
if ($result.StartsWith('.\')) # remove '.\'.
{
$result = $result.SubString(2)
}
$result
}
像这样称呼它:
> NormalizePath "fred\frog\..\frag"
fred\frag
请注意,此代码段需要 DLL 的路径。您可以使用一个技巧来查找包含当前正在执行的脚本的文件夹,但在我的情况下,我有一个可以使用的环境变量,所以我只是使用了它。
这给出了完整路径:
(gci 'fred\frog\..\frag').FullName
这给出了相对于当前目录的路径:
(gci 'fred\frog\..\frag').FullName.Replace((gl).Path + '\', '')
出于某种原因,它们仅frag
在文件而不是directory
.
创建一个函数。此功能将规范化系统上不存在的路径以及不添加驱动器号。
function RemoveDotsInPath {
[cmdletbinding()]
Param( [Parameter(Position=0, Mandatory=$true)] [string] $PathString = '' )
$newPath = $PathString -creplace '(?<grp>[^\n\\]+\\)+(?<-grp>\.\.\\)+(?(grp)(?!))', ''
return $newPath
}
前任:
$a = 'fooA\obj\BusinessLayer\..\..\bin\BusinessLayer\foo.txt'
RemoveDotsInPath $a
'fooA\bin\BusinessLayer\foo.txt'
感谢 Oliver Schadlich 在 RegEx 方面的帮助。
如果您需要摆脱 .. 部分,您可以使用 System.IO.DirectoryInfo 对象。在构造函数中使用“fred\frog..\frag”。FullName 属性将为您提供规范化的目录名称。
唯一的缺点是它会给你完整的路径(例如c:\test\fred\frag)。
此处注释的权宜之计部分结合在一起,使它们统一了相对路径和绝对路径:
[System.IO.Directory]::SetCurrentDirectory($pwd)
[IO.Path]::GetFullPath($dapath)
一些样本:
$fps = '.', 'file.txt', '.\file.txt', '..\file.txt', 'c:\somewhere\file.txt'
$fps | % { [IO.Path]::GetFullPath($_) }
输出:
C:\Users\thelonius\tests
C:\Users\thelonius\tests\file.txt
C:\Users\thelonius\tests\file.txt
C:\Users\thelonius\file.txt
c:\somewhere\file.txt
好吧,一种方法是:
Join-Path 'fred\frog' '..\frag'.Replace('..', '')
等等,也许我误解了这个问题。在您的示例中,frag 是青蛙的子文件夹吗?