私には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
_
個人的にも複雑ではありません、私はこのために外部スクリプトに依存するソリューションを軽daします、それは_Join-Path
_とpwd
(GetFullPath
が単にそれを作ることでかなり適切に解決される単純な問題ですかなり)。 相対部分のみのみを保持する場合は、.Substring((pwd).Path.Trim('\').Length + 1)
と出来上がりを追加するだけです!
_fred\frag
_
_C:\
_ Edgeケースを指摘してくれた@Dangphに感謝します。
Resolve-pathを使用して、..\fragをフルパスに展開できます。
PS > resolve-path ..\frag
Compose()メソッドを使用してパスを正規化してみてください:
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
Path.GetFullPath を使用することもできますが、(ダン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のプロバイダーモデルでは、PowerShellの現在のパスをWindowsがプロセスの作業ディレクトリと見なすものと異なるため、PowerShell以外のパス操作関数(System.IO.Path内の関数など)はPowerShellから信頼できません。
また、既に発見したかもしれませんが、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 。
EDIT:これは私が思いついたものです:
[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へのパスが必要であることに注意してください。現在実行中のスクリプトを含むフォルダーを見つけるために使用できるトリックがありますが、私の場合、使用できる環境変数があったので、それを使用しました。
関数を作成します。この関数は、システムに存在しないパスを正規化し、ドライブ文字を追加しません。
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に感謝します。
これにより、完全なパスが得られます。
(gci 'fred\frog\..\frag').FullName
これにより、現在のディレクトリからの相対パスが得られます。
(gci 'fred\frog\..\frag').FullName.Replace((gl).Path + '\', '')
何らかの理由で、frag
がdirectory
ではなくファイルである場合にのみ機能します。
パスに修飾子(ドライブ文字)が含まれている場合、- 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
さて、1つの方法は次のとおりです。
Join-Path 'fred\frog' '..\frag'.Replace('..', '')
待って、多分私は質問を誤解しています。あなたの例では、fragはカエルのサブフォルダーですか?
..部分を削除する必要がある場合は、System.IO.DirectoryInfoオブジェクトを使用できます。コンストラクターで 'fred\frog ..\frag'を使用します。 FullNameプロパティは、正規化されたディレクトリ名を提供します。
唯一の欠点は、完全なパス(c:\ test\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