109

私には2つの道があります:

fred\frog

..\frag

次のように、PowerShell でそれらを結合できます。

join-path 'fred\frog' '..\frag'

それは私にこれを与えます:

fred\frog\..\frag

しかし、私はそれを望んでいません。次のように、二重ドットのない正規化されたパスが必要です。

fred\frag

どうすればそれを手に入れることができますか?

4

12 に答える 12

110

resolve-pathを使用して、..\fragをフルパスに展開できます。

PS > resolve-path ..\frag 

Combine()メソッドを使用してパスを正規化してみてください。

[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
于 2009-01-31T16:25:10.000 に答える
89

との組み合わせ$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に感謝します。

于 2012-12-12T19:39:35.883 に答える
26

Path.GetFullPathを使用することもできますが、(Dan Rの回答と同様に)これによりパス全体が得られます。使用法は次のようになります。

[IO.Path]::GetFullPath( "fred\frog\..\frag" )

またはもっと興味深いことに

[IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") )

どちらも次のようになります (現在のディレクトリが D:\ であると仮定します):

D:\fred\frag

このメソッドは、fred または frag が実際に存在するかどうかを判断しようとしないことに注意してください。

于 2009-01-30T15:22:06.447 に答える
24

受け入れられた答えは大きな助けになりましたが、絶対パスも適切に「正規化」しません。絶対パスと相対パスの両方を正規化する私の派生作品を以下に示します。

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;
}
于 2013-06-06T14:18:24.543 に答える
14

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($_)
        }
    }
}
于 2011-02-13T02:51:55.270 に答える
3

このライブラリは優れています: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へのパスが必要であることに注意してください。現在実行中のスクリプトを含むフォルダーを見つけるために使用できるトリックがありますが、私の場合は使用できる環境変数があったので、それを使用しました。

于 2009-02-28T05:05:50.457 に答える
1

これにより、フルパスが得られます。

(gci 'fred\frog\..\frag').FullName

これにより、現在のディレクトリからの相対パスが得られます。

(gci 'fred\frog\..\frag').FullName.Replace((gl).Path + '\', '')

何らかの理由でfrag、がファイルであり、ではない場合にのみ機能しますdirectory

于 2009-01-31T01:46:27.417 に答える
1

関数を作成します。この機能は、システムに存在しないパスを正規化し、ドライブ文字を追加しません。

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 に感謝します。

于 2012-07-20T22:57:03.023 に答える
0

.. 部分を取り除く必要がある場合は、System.IO.DirectoryInfo オブジェクトを使用できます。コンストラクターで「fred\frog..\frag」を使用します。FullName プロパティは、正規化されたディレクトリ名を提供します。

唯一の欠点は、パス全体が表示されることです (例: c:\test\fred\frag)。

于 2009-01-30T14:37:06.927 に答える
-1

さて、1つの方法は次のとおりです。

Join-Path 'fred\frog' '..\frag'.Replace('..', '')

待ってください、多分私は質問を誤解しています。あなたの例では、フラグはカエルのサブフォルダーですか?

于 2009-01-30T14:26:08.960 に答える