私には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
どうすればそれを手に入れることができますか?
resolve-pathを使用して、..\fragをフルパスに展開できます。
PS > resolve-path ..\frag
Combine()メソッドを使用してパスを正規化してみてください。
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
との組み合わせ$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
絶対ベースで、.NETAPIを安全に呼び出すことができるようになりましたGetFullPath
。
[System.IO.Path]::GetFullPath((Join-Path (Join-Path $pwd fred\frog) '..\frag'))
..
これにより、正しく解決された完全修飾パスが得られます。
C:\WINDOWS\system32\fred\frag
個人的にも複雑ではありませんが、これを外部スクリプトに依存するソリューションは軽蔑しています。単純な問題は、andによってかなり適切に解決されますJoin-Path
($pwd
単にGetFullPath
きれいにするためです)。相対的な部分だけを残したい場合は、追加.Substring($pwd.Path.Trim('\').Length + 1)
して出来上がり!
fred\frag
C:\
エッジケースを指摘してくれた@Dangphに感謝します。
Path.GetFullPathを使用することもできますが、(Dan Rの回答と同様に)これによりパス全体が得られます。使用法は次のようになります。
[IO.Path]::GetFullPath( "fred\frog\..\frag" )
またはもっと興味深いことに
[IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") )
どちらも次のようになります (現在のディレクトリが D:\ であると仮定します):
D:\fred\frag
このメソッドは、fred または frag が実際に存在するかどうかを判断しようとしないことに注意してください。
受け入れられた答えは大きな助けになりましたが、絶対パスも適切に「正規化」しません。絶対パスと相対パスの両方を正規化する私の派生作品を以下に示します。
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 以外のパス操作関数 (System.IO.Path 内のものなど) は、PowerShell からは信頼できません。これは、PowerShell のプロバイダー モデルにより、PowerShell の現在のパスが、Windows がプロセスの作業ディレクトリと見なすパスと異なることが許可されているためです。
また、既にお気づきかもしれませんが、PowerShell の Resolve-Path および Convert-Path コマンドレットは、相対パス (「..」を含むもの) をドライブ修飾絶対パスに変換するのに役立ちますが、参照されているパスが存在しない場合は失敗します。
次の非常に単純なコマンドレットは、存在しないパスに対して機能するはずです。「fred」または「frag」ファイルまたはフォルダーが見つからない場合でも、「fred\frog\..\frag」を「d:\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($_)
}
}
}
このライブラリは優れています: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 に感謝します。
.. 部分を取り除く必要がある場合は、System.IO.DirectoryInfo オブジェクトを使用できます。コンストラクターで「fred\frog..\frag」を使用します。FullName プロパティは、正規化されたディレクトリ名を提供します。
唯一の欠点は、パス全体が表示されることです (例: c:\test\fred\frag)。
さて、1つの方法は次のとおりです。
Join-Path 'fred\frog' '..\frag'.Replace('..', '')
待ってください、多分私は質問を誤解しています。あなたの例では、フラグはカエルのサブフォルダーですか?