[powershell] 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)는 프로세스의 현재 작업 디렉터리를 변경하지 않기 때문에 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에게 감사드립니다 .


답변

resolve-path를 사용하여 .. \ frag를 전체 경로로 확장 할 수 있습니다.

PS > resolve-path ..\frag 

Combine () 메서드를 사용하여 경로를 정규화하십시오.

[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)


답변

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의 공급자 모델을 사용하면 PowerShell의 현재 경로가 Windows에서 프로세스의 작업 디렉터리라고 생각하는 것과 다를 수 있기 때문에 PowerShell이 ​​아닌 경로 조작 기능 (예 : System.IO.Path의 기능)은 PowerShell에서 신뢰할 수 없습니다.

또한 이미 발견 한 것처럼 PowerShell의 Resolve-Path 및 Convert-Path cmdlet은 상대 경로 ( ‘..’s 포함)를 드라이브 한정 절대 경로로 변환하는 데 유용하지만 참조 된 경로가 존재하지 않으면 실패합니다.

다음의 매우 간단한 cmdlet은 존재하지 않는 경로에 대해 작동합니다. ‘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.