我有兩條路:如何規範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