tutorial - Powershell: ¿resolver camino que podría no existir?
powershell tutorial (10)
Estoy tratando de procesar una lista de archivos que pueden o no estar actualizados y pueden existir o no. Al hacerlo, necesito resolver la ruta completa de un elemento, aunque el elemento se pueda especificar con rutas relativas. Sin embargo, Resolve-Path
imprime y produce errores cuando se utiliza con un archivo inexistente.
Por ejemplo, ¿Cuál es la forma más simple y limpia de resolver "./newdir/newfile.txt"
a "C:/Current/Working/Directory/newdir/newfile.txt"
en Powershell ?
Tenga en cuenta que el método estático de System.IO.Path
usa con el directorio de trabajo del proceso, que no es la ubicación actual de powershell.
Aquí hay una respuesta aceptada, pero es bastante larga y hay una alternativa más simple disponible.
En cualquier versión reciente de Powershell, puede usar Test-Path -IsValid -Path ''C:/Probably Fake/Path.txt''
Esto simplemente verifica que no haya caracteres ilegales en la ruta y que la ruta se pueda usar para almacenar un archivo. Si el destino no existe, a Test-Path
no le importará en este caso, solo se le pedirá que pruebe si la ruta proporcionada es potencialmente válida.
Creo que estás en el camino correcto. Simplemente use [Environment] :: CurrentDirectory para establecer la noción de .NET del directorio actual del proceso, por ejemplo:
[Environment]::CurrentDirectory = $pwd
[IO.Path]::GetFullPath("./xyz")
Cuando Resolve-Path
falla debido a que el archivo no existe, se puede acceder a la ruta completamente resuelta desde el objeto de error lanzado.
Puede usar una función como la siguiente para corregir Resolve-Path
y hacer que funcione como esperaba.
function Force-Resolve-Path {
<#
.SYNOPSIS
Calls Resolve-Path but works for files that don''t exist.
.REMARKS
From http://devhawk.net/blog/2010/1/22/fixing-powershells-busted-resolve-path-cmdlet
#>
param (
[string] $FileName
)
$FileName = Resolve-Path $FileName -ErrorAction SilentlyContinue `
-ErrorVariable _frperror
if (-not($FileName)) {
$FileName = $_frperror[0].TargetObject
}
return $FileName
}
Descubrí que lo siguiente funciona bastante bien.
$workingDirectory = Convert-Path (Resolve-Path -path ".")
$newFile = "newDir/newFile.txt"
Do-Something-With "$workingDirectory/$newFile"
Convert-Path se puede utilizar para obtener la ruta como una cadena, aunque este no es siempre el caso. Vea this entrada en COnvert-Path para más detalles.
Esto tiene la ventaja de no tener que establecer el directorio actual de CLR Environment:
[IO.Path]::Combine($pwd,"non/existing/path")
NOTA
Esto no es funcionalmente equivalente a la respuesta de x0n . System.IO.Path.Combine
solo combina segmentos de ruta de cadena. Su utilidad principal es evitar que el desarrollador tenga que preocuparse por las barras. GetUnresolvedProviderPathFromPSPath
recorrerá la ruta de entrada relativa al presente directorio de trabajo, de acuerdo con .
''s y ..
'' s.
Puedes simplemente configurar -errorAction como "SilentlyContinue" y usar Resolve-Path
5 > (Resolve-Path ./AllFilerData.xml -ea 0).Path
C:/Users/Andy.Schneider/Documents/WindowsPowerShell/Scripts/AllFilerData.xml
6 > (Resolve-Path ./DoesNotExist -ea 0).Path
7 >
Usted quiere:
c:/path/exists/> $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("./nonexist/foo.txt")
devoluciones:
c:/path/exists/nonexists/foo.txt
Esto tiene la ventaja de trabajar con PSPaths, no con rutas de sistema de archivos nativas. Un PSPAth puede no asignar 1-1 a una ruta del sistema de archivos, por ejemplo, si monta una unidad psdrive con un nombre de unidad de varias letras.
-Oisin
Verifique si el archivo existe antes de resolver:
if(Test-Path ./newdir/newfile.txt) { (Resolve-Path ./newdir/newfile.txt).Path }
Join-Path (Resolve-Path .) newdir/newfile.txt
function Get-FullName()
{
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline = $True)] [object[]] $Path
)
Begin{
$Path = @($Path);
}
Process{
foreach($p in $Path)
{
if($p -eq $null -or $p -match ''^/s*$''){$p = [IO.Path]::GetFullPath(".");}
elseif($p -is [System.IO.FileInfo]){$p = $p.FullName;}
else{$p = [IO.Path]::GetFullPath($p);}
$p;
}
}
}