我有两条路:
fred\frog
和
..\frag
我可以像这样在PowerShell中加入它们:
join-path 'fred\frog' '..\frag'
这给了我这个:
fred\frog\..\frag
但我不希望如此。我想要一个没有双点的标准化路径,如下所示:
fred\frag
我怎么能得到它?
答案 0 :(得分:96)
您可以使用resolve-path将<\ frag扩展为其完整路径:
PS > resolve-path ..\frag
尝试使用combine()方法规范化路径:
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
答案 1 :(得分:72)
您可以使用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
和pwd
而GetFullPath
恰好解决的简单问题(.Substring((pwd).Path.Trim('\').Length + 1)
只是为了制作它很漂亮)。如果您只想保留仅相关部分,则只需添加fred\frag
即可!
C:\
感谢@Dangph指出{{1}}边缘情况。
答案 2 :(得分:22)
您也可以使用Path.GetFullPath,尽管(与Dan R的回答一样),这将为您提供完整的路径。用法如下:
[IO.Path]::GetFullPath( "fred\frog\..\frag" )
或者更有趣的是
[IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") )
这两个产生以下结果(假设您当前的目录是D:\):
D:\fred\frag
请注意,此方法不会尝试确定fred或frag是否实际存在。
答案 3 :(得分:16)
接受的答案是一个很大的帮助,但它也没有正确地“正常化”绝对路径。在下面找到我的衍生作品,它可以规范绝对路径和相对路径。
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;
}
答案 4 :(得分: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($_)
}
}
}
答案 5 :(得分:3)
这个图书馆很好: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的路径。有一个技巧可以用来找到包含当前正在执行的脚本的文件夹,但在我的情况下,我有一个我可以使用的环境变量,所以我只是使用它。
答案 6 :(得分:2)
创建一个功能。此函数将规范化系统中不存在的路径,并且不添加驱动器号。
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中寻求帮助。
答案 7 :(得分:1)
这给出了完整的路径:
(gci 'fred\frog\..\frag').FullName
这给出了相对于当前目录的路径:
(gci 'fred\frog\..\frag').FullName.Replace((gl).Path + '\', '')
出于某种原因,只有当frag
是文件而不是directory
时,它们才有效。
答案 8 :(得分:1)
如果路径包含限定符(驱动器号),则x0n's answer to Powershell: resolve path that might not exist?将对路径进行规范化。如果该路径不包含限定符,它仍将被规范化,但将返回相对于当前目录的完全限定路径,这可能不是您想要的。
$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
答案 9 :(得分:0)
嗯,一种方法是:
Join-Path 'fred\frog' '..\frag'.Replace('..', '')
等等,也许我误解了这个问题。在你的例子中,是否是青蛙的子文件夹?
答案 10 :(得分:0)
如果需要删除..部分,可以使用System.IO.DirectoryInfo对象。在构造函数中使用'fred \ frog .. \ frag'。 FullName属性将为您提供规范化的目录名称。
唯一的缺点是它会给你整个路径(例如c:\ test \ fred \ frag)。
答案 11 :(得分:0)
这里评论的权宜部分结合在一起,使它们统一了相对和绝对的路径:
[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