두 가지 경로가 있습니다.
fred\frog
과
..\frag
다음과 같이 PowerShell에서 함께 조인 할 수 있습니다.
join-path 'fred\frog' '..\frag'
그것은 나에게 이것을 준다 :
fred\frog\..\frag
그러나 나는 그것을 원하지 않는다. 다음과 같이 이중 점이없는 정규화 된 경로를 원합니다.
fred\frag
어떻게 얻을 수 있습니까?
두 가지 경로가 있습니다.
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\ 동일한 경로하지만 두 개의 서로 다른 결과
[io.path]::Combine가 반전됩니다. 더 좋은 방법은 기본 Join-PathPowerShell 명령을 사용하는 것입니다 . 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의 공급자 모델을 사용하면 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($_)
}
}
}
Get-AbsolutePath q:\foo\bar\..\baz유효한 경로인데도 실패합니다. 글쎄, 유효한 경로에 대한 정의에 따라. :-) FWIW, 심지어는 Test-Path <path> -IsValid존재하지 않는 드라이브에 루트가있는 경로 에서 내장 오류가 발생합니다.
HKLM:\SOFTWARE의 SOFTWARE키를 참조하는 PowerShell의 유효한 경로입니다 . 그러나 그것이 유효한지 알아 내려면 레지스트리 경로에 대한 규칙이 무엇인지 파악해야합니다.
이 라이브러리는 좋습니다 : 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