У меня два пути:
fred\frog
а также
..\frag
Я могу объединить их в PowerShell следующим образом:
join-path 'fred\frog' '..\frag'
Это дает мне следующее:
fred\frog\..\frag
Но я этого не хочу. Мне нужен нормализованный путь без двойных точек, например:
fred\frag
Как я могу это получить?
powershell
path
дан-гф
источник
источник
Ответы:
Вы можете использовать комбинацию
pwd
,Join-Path
и[System.IO.Path]::GetFullPath
получить полную расширенный путь.Поскольку
cd
(Set-Location
) не изменяет текущий рабочий каталог процесса, простая передача относительного имени файла в .NET API, который не понимает контекст PowerShell, может иметь непреднамеренные побочные эффекты, такие как разрешение на путь, основанный на исходной рабочей каталог (не ваше текущее местоположение).Что вы делаете, это сначала определяете свой путь:
Join-Path (Join-Path (pwd) fred\frog) '..\frag'
Это дает (учитывая мое текущее местоположение):
Имея абсолютную базу, можно безопасно вызывать .NET API
GetFullPath
:[System.IO.Path]::GetFullPath((Join-Path (Join-Path (pwd) fred\frog) '..\frag'))
Что дает вам полный путь и с
..
удаленными:Это тоже несложно, лично я пренебрегаю решениями, которые зависят от внешних скриптов для этого, это простая проблема, довольно удачно решенная с помощью
Join-Path
иpwd
(GetFullPath
просто чтобы сделать это красиво). Если вы хотите сохранить только относительную часть , вы просто добавляете.Substring((pwd).Path.Trim('\').Length + 1)
и вуаля!ОБНОВИТЬ
Спасибо @Dangph за указание на крайний
C:\
случай.источник
cd c:\; "C:\fred\frag".Substring((pwd).Path.Length + 1)
. Это не имеет большого значения; просто то, о чем нужно знать.cd c:\; "C:\fred\frag".Substring((pwd).Path.Trim('\').Length + 1)
. Хотя это становится довольно долгим.Вы можете развернуть .. \ frag до полного пути с помощью команды resol-path:
Попробуйте нормализовать путь с помощью метода comb ():
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)
источник
C:\Windows
противC:\Windows\
того же пути , но два разных результатов[io.path]::Combine
меняются местами. А еще лучше использовать собственнуюJoin-Path
команду PowerShell:Join-Path (Resolve-Path ..\frag).Path 'fred\frog'
также обратите внимание, что, по крайней мере, начиная с PowerShell v3,Resolve-Path
теперь поддерживает-Relative
переключатель для разрешения на путь относительно текущей папки. Как уже упоминалось,Resolve-Path
работает только с существующими путями, в отличие от[IO.Path]::GetFullPath()
.Вы также можете использовать Path.GetFullPath , хотя (как и в случае с ответом Дэна Р.) это даст вам весь путь. Использование будет следующим:
[IO.Path]::GetFullPath( "fred\frog\..\frag" )
или более интересно
[IO.Path]::GetFullPath( (join-path "fred\frog" "..\frag") )
оба из которых дают следующее (при условии, что ваш текущий каталог - D: \):
Обратите внимание, что этот метод не пытается определить, существует ли на самом деле fred или frag.
источник
[System.IO.Directory]::SetCurrentDirectory(((Get-Location -PSProvider FileSystem).ProviderPath))
[IO.Path]::GetFullPath()
отличие от собственного PowerShellResolve-Path
, он также работает с несуществующими путями. Его недостатком является необходимость сначала синхронизировать рабочую папку .NET с PS, как указывает @JasonMArcher.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 (например, в System.IO.Path), не будут надежными из PowerShell, поскольку модель поставщика PowerShell позволяет текущему пути PowerShell отличаться от того, что Windows считает рабочим каталогом процесса.
Кроме того, как вы, возможно, уже заметили, командлеты PowerShell Resolve-Path и Convert-Path полезны для преобразования относительных путей (содержащих символы "..") в абсолютные пути с указанием диска, но они не работают, если указанный путь не существует.
Следующий очень простой командлет должен работать для несуществующих путей. Он преобразует 'fred \ frog \ .. \ frag' в 'd: \ fred \ frag', даже если файл или папку '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
это допустимый путь в PowerShell, относящийся кSOFTWARE
ключу в кусте реестра локального компьютера. Но чтобы выяснить, действительно ли он действителен, необходимо выяснить, каковы правила для путей реестра.Хорошая библиотека: 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.
источник
somepaththing\.\filename.txt
что он сохраняет эту единственную точкуЕсли путь включает квалификатор (букву диска), то ответ x0n на Powershell: разрешить путь, который может не существовать? нормализует путь. Если путь не включает квалификатор, он все равно будет нормализован, но вернет полный путь относительно текущего каталога, что может быть не тем, что вам нужно.
$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.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($_) }
выход:
источник
Ну, один из способов:
Join-Path 'fred\frog' '..\frag'.Replace('..', '')
Подождите, может я неправильно понял вопрос. В вашем примере является ли фрагмент вложенной папкой лягушки?
источник