私には2つのパスがあります。
fred\frog
そして
..\frag
PowerShellで次のように結合できます。
join-path 'fred\frog' '..\frag'
それは私にこれを与えます:
fred\frog\..\frag
しかし、私はそれを望んでいません。次のように、二重ドットのない正規化されたパスが必要です。
fred\frag
どうすれば入手できますか?
私には2つのパスがあります。
fred\frog
そして
..\frag
PowerShellで次のように結合できます。
join-path 'fred\frog' '..\frag'
それは私にこれを与えます:
fred\frog\..\frag
しかし、私はそれを望んでいません。次のように、二重ドットのない正規化されたパスが必要です。
fred\frag
どうすれば入手できますか?
回答:
あなたは、の組み合わせを使用することができ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に感謝します。
cd c:\; "C:\fred\frag".Substring((pwd).Path.Length + 1)
ます:。たいしたことじゃない; 知っておくべきことだけです。
cd c:\; "C:\fred\frag".Substring((pwd).Path.Trim('\').Length + 1)
。少し長くなってきています。
resolve-pathを使用して、.. \ fragを完全なパスに展開できます。
PS > resolve-path ..\frag
Combine()メソッドを使用してパスを正規化してみてください:
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
C:\Windows
対C:\Windows\
同じパスが、2つの異なる結果
[io.path]::Combine
が逆になります。さらにJoin-Path
便利なのは、ネイティブのPowerShellコマンドを使用することです。Join-Path (Resolve-Path ..\frag).Path 'fred\frog'
また、少なくともPowerShell v3では、現在のフォルダーからの相対パスに解決するためResolve-Path
の-Relative
スイッチがサポートされるようになりました。前述のようにResolve-Path
、とは異なり、は既存のパスでのみ機能します[IO.Path]::GetFullPath()
。
Path.GetFullPathを使用することもできますが、(Dan Rの回答と同様に)これによりパス全体が得られます。使用法は次のようになります。
[IO.Path]::GetFullPath( "fred\frog\..\frag" )
より興味深い
[IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") )
どちらも次の結果になります(現在のディレクトリがD:\であると想定)。
D:\fred\frag
このメソッドは、fredまたはfragが実際に存在するかどうかを判断しようとしないことに注意してください。
[System.IO.Directory]::SetCurrentDirectory(((Get-Location -PSProvider FileSystem).ProviderPath))
[IO.Path]::GetFullPath()
、PowerShellのネイティブとは異なりResolve-Path
、存在しないパスでも機能します。その欠点は、@ JasonMArcherが指摘するように、最初に.NETの作業フォルダーをPSと同期する必要があることです。
Join-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;
}
[IO.Path]::GetFullPath()
プレーンなファイル名のディレクトリを正しく決定していません。
PowerShell以外のパス操作関数(System.IO.Pathの関数など)は、PowerShellから信頼できません。これは、PowerShellのプロバイダーモデルでは、PowerShellの現在のパスが、Windowsがプロセスの作業ディレクトリと見なしているパスと異なるためです。
また、既にお気づきかもしれませんが、PowerShellのResolve-PathおよびConvert-Pathコマンドレットは、相対パス(「..」を含むもの)をドライブ修飾された絶対パスに変換するのに役立ちますが、参照されるパスが存在しない場合は失敗します。
次の非常に単純なコマンドレットは、存在しないパスに対して機能します。「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($_)
}
}
}
Get-AbsolutePath q:\foo\bar\..\baz
有効なパスであっても失敗します。まあ、有効なパスの定義に応じて。:-) FWIW、組み込みであっても、Test-Path <path> -IsValid
存在しないドライブをルートとするパスで失敗します。
HKLM:\SOFTWARE
を参照するPowerShellの有効なパスですSOFTWARE
。しかし、それが有効かどうかを判断するには、レジストリパスのルールが何であるかを把握する必要があります。
このライブラリは適切です: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'
RegExのサポートを提供してくれたOliver Schadlichに感謝します。
somepaththing\.\filename.txt
、単一のドットを保持するようなパスでは機能しないことに注意してください
パスに修飾子(ドライブ文字)が含まれている場合、Powershellに対するx0nの回答:存在しない可能性のあるパスを解決しますか?パスを正規化します。パスに修飾子が含まれていない場合でも、正規化されますが、現在のディレクトリからの完全修飾パスが返されます。
$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
ここでのコメントの適切な部分は、相対パスと絶対パスを統合するように組み合わされています。
[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はカエルのサブフォルダーですか?