我有两条路:如何规范PowerShell中的路径?
fred\frog
和
..\frag
我可以在PowerShell中一起加入他们这样的:
join-path 'fred\frog' '..\frag'
这给了我这样的:
fred\frog\..\frag
但我不想那样。我想要一个没有双点的标准化路径,如下所示:
fred\frag
我该如何得到它?
我有两条路:如何规范PowerShell中的路径?
fred\frog
和
..\frag
我可以在PowerShell中一起加入他们这样的:
join-path 'fred\frog' '..\frag'
这给了我这样的:
fred\frog\..\frag
但我不想那样。我想要一个没有双点的标准化路径,如下所示:
fred\frag
我该如何得到它?
您可以使用pwd
,Join-Path
和[System.IO.Path]::GetFullPath
的组合来获得完全限定的扩展路径。
由于cd
(Set-Location
)不会改变进程当前工作目录,只是传递一个相对的文件名到.NET API不理解PowerShell的情况下,可以产生意想不到的副作用,如解决的路径基于最初的工作目录(而不是您当前的位置)。
你要做的就是首先符合您的路径:
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
UPDATE
由于@Dangph用于指出了C:\
边缘情况。
那么,一个办法是:
Join-Path 'fred\frog' '..\frag'.Replace('..', '')
等待,也许是我误解了问题。在你的例子中,frag是青蛙的子文件夹吗?
”是frag的青蛙子文件夹吗?“不。..意味着升一级。 frag是fred中的子文件夹(或文件)。 – 2009-01-31 01:48:33
如果您需要摆脱..部分,您可以使用System.IO.DirectoryInfo对象。在构造函数中使用'fred \ frog .. \ frag'。 FullName属性将为您提供规范化的目录名称。
唯一的缺点是它会给你整个路径(例如c:\ test \ fred \ frag)。
你也可以使用Path.GetFullPath,虽然(与丹R的答案一样),这会给你整个路径。用法是如下:
[IO.Path]::GetFullPath("fred\frog\..\frag")
或更有趣
[IO.Path]::GetFullPath((join-path "fred\frog" "..\frag"))
两者产生以下(假设你的当前目录是d:\):
D:\fred\frag
注意,这方法不会尝试确定fred或frag是否实际存在。
接近了,但是当我尝试它时,即使我当前的目录是“C:\ scratch”,也会得到“H:\ fred \ frag”,这是错误的。 (根据MSDN,它不应该这样做。)但是,它给了我一个想法。我将添加它作为答案。 – 2009-01-31 01:37:50
你的问题是你需要在.NET中设置当前目录。 `[System.IO.Directory] :: SetCurrentDirectory(((Get-Location-PSProvider FileSystem).ProviderPath))` – JasonMArcher 2011-08-16 04:47:00
只需明确声明:`[IO.Path] :: GetFullPath()`,与PowerShell本地` “Resolve-Path”也适用于不存在的路径。它的缺点是需要首先同步.NET的工作文件夹,正如@JasonMArcher指出的那样。 – mklement0 2013-03-11 23:45:45
这使的完整路径:
(gci 'fred\frog\..\frag').FullName
此路径相对于给到当前目录:
(gci 'fred\frog\..\frag').FullName.Replace((gl).Path + '\', '')
出于某种原因,他们只工作,如果frag
是一个文件,而不是directory
。
gci是get-childitem的别名。目录的子项是其内容。用gi替换gci,它应该适用于两者。 – zdan 2009-01-31 02:43:02
Get-Item很好地工作。但是,这种方法同样需要存在文件夹。 – 2012-05-15 09:58:34
您还可以扩大.. \断枝它与解决路径完整路径:
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
这个库是好的:
PS > resolve-path ..\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。有一个技巧可以用来查找包含当前正在执行的脚本的文件夹,但在我的情况下,我有一个我可以使用的环境变量,所以我只是用它。
任何非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($_)
}
}
}
创建一个函数。此功能将标准化系统中不存在的路径,也不会添加驱动器号。
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'
要感谢的是奥利弗Schadlich在正则表达式的帮助。
接受的答案是一个很大的帮助,但它并没有适当地“规范化”一条绝对路径。在下面找到我的派生工作,它将绝对和相对路径归一化。
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;
}
意见的权宜之计部分在这里结合,使得它们统一的相对和绝对路径:
[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
是frag是青蛙的子文件夹?如果没有,那么结合路径会让你fred \ frog \ frag。如果这是一个非常不同的问题。 “ – EBGreen 2009-01-30 14:41:46