如何规范PowerShell中的path?

我有两条path:

fred\frog 

 ..\frag 

我可以像这样在PowerShell中一起join:

 join-path 'fred\frog' '..\frag' 

这给了我这个:

 fred\frog\..\frag 

但我不想那样 我想要一个没有双点的标准化path,就像这样:

 fred\frag 

我怎么能得到这个?

您可以使用pwdJoin-Path[System.IO.Path]::GetFullPath来获取完全限定的扩展path。

由于cdSet-Location )不改变进程当前的工作目录,简单地传递一个相对的文件名到一个不理解PowerShell上下文的.NET API,可能会产生意想不到的副作用,例如parsing为基于pathclosures最初的工作目录(不是你目前的位置)。

你做什么是你第一次限定你的path:

 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')) 

这给你完全合格的path和..删除:

 C:\WINDOWS\system32\fred\frag 

这并不复杂,个人而言,我蔑视依赖于外部脚本的解决scheme,这是一个简单的问题,相当适合通过Join-PathpwdGetFullPath只是为了让它变得漂亮)解决。 如果你只想保留相对的部分 ,你只需添加.Substring((pwd).Path.Trim('\').Length + 1) ,瞧!

 fred\frag 

UPDATE

感谢@Dangph指出了C:\边界情况。

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

 PS > resolve-path ..\frag 

尝试使用combine()方法来标准化path:

 [io.path]::Combine("fred\frog",(resolve-path ..\frag).path) 

你也可以使用Path.GetFullPath ,虽然(和Dan R的答案一样),这会给你整个path。 用法如下:

 [IO.Path]::GetFullPath( "fred\frog\..\frag" ) 

或者更有趣

 [IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") ) 

这两个产生以下(假设您的当前目录是D:\):

 D:\fred\frag 

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

接受的答案是一个很大的帮助,但是它不能正常地“规范”一个绝对path。 在下面find我的派生工作,使绝对和相对path归一化。

 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的任何非PowerShellpath操作函数(如System.IO.Path中的那些函数)都不可靠,因为PowerShell的提供程序模型允许PowerShell的当前path与Windows认为进程的工作目录不同。

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

以下非常简单的cmdlet应该适用于不存在的path。 即使无法find'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($_) } } } 

这个库很好: 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的path。 有一个技巧可以用来find包含当前正在执行的脚本的文件夹,但在我的情况下,我有一个我可以使用的环境variables,所以我只是用它。

创build一个函数。 此function将标准化系统中不存在的path,也不会添加驱动器号。

 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的帮助。

这给出了完整的path:

 (gci 'fred\frog\..\frag').FullName 

这给出了相对于当前目录的path:

 (gci 'fred\frog\..\frag').FullName.Replace((gl).Path + '\', '') 

出于某种原因,只有在frag是文件而不是directory ,它们才能工作。

那么,一种方法是:

 Join-Path 'fred\frog' '..\frag'.Replace('..', '') 

等等,也许我误解了这个问题。 在你的例子中,frag是一个青蛙的子文件夹吗?

如果你需要摆脱..部分,你可以使用System.IO.DirectoryInfo对象。 在构造函数中使用'fred \ frog .. \ frag'。 FullName属性将为您提供规范化的目录名称。

唯一的缺点是它会给你整个path(例如c:\ test \ fred \ frag)。