我正在尝试处理可能是也可能不是最新的文件列表,可能存在也可能不存在。在这样做时,我需要解析项目的完整路径,即使该项目可能使用相对路径指定。但是,Resolve-Path
在与不存在的文件一起使用时会打印并出错。
例如,在Powershell中解析".\newdir\newfile.txt"
到"C:\Current\Working\Directory\newdir\newfile.txt"
的最简单,最干净的方法是什么?
请注意,System.IO.Path
的静态方法与进程的工作目录一起使用 - 这不是powershell的当前位置。
答案 0 :(得分:71)
你想:
c:\path\exists\> $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath(".\nonexist\foo.txt")
返回:
c:\path\exists\nonexists\foo.txt
这样做的好处是可以使用PSPath,而不是本机文件系统路径。 PSPAth可能不会将1-1映射到文件系统路径,例如,如果您使用多字母驱动器名称挂载psdrive。
-Oisin
答案 1 :(得分:23)
当Resolve-Path
由于文件不存在而失败时,可以从抛出的错误对象访问完全解析的路径。
您可以使用以下功能修复Resolve-Path
并使其按预期工作。
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
}
答案 2 :(得分:13)
我认为你走的是正确的道路。只需使用[Environment] :: CurrentDirectory设置.NET的进程当前目录的概念,例如:
[Environment]::CurrentDirectory = $pwd
[IO.Path]::GetFullPath(".\xyz")
答案 3 :(得分:5)
这样做的好处是无需设置CLR环境的当前目录:
[IO.Path]::Combine($pwd,"non\existing\path")
这在功能上与x0n's answer不同。 System.IO.Path.Combine
仅组合字符串路径段。它的主要功能是让开发人员不必担心斜线。根据{{1}}和GetUnresolvedProviderPathFromPSPath
,.
将遍历相对于当前工作目录的输入路径。
答案 4 :(得分:4)
Join-Path (Resolve-Path .) newdir\newfile.txt
答案 5 :(得分:1)
我发现以下内容效果不错。
$workingDirectory = Convert-Path (Resolve-Path -path ".")
$newFile = "newDir\newFile.txt"
Do-Something-With "$workingDirectory\$newFile"
Convert-Path可用于将路径作为字符串获取,但情况并非总是如此。有关详细信息,请参阅COnvert-Path上的this条目。
答案 6 :(得分:1)
这里有一个公认的答案,但它很长,并且有一个更简单的替代方案。
在任何最新版本的Powershell中,您都可以使用Test-Path -IsValid -Path 'C:\Probably Fake\Path.txt'
这只是验证路径中没有非法字符,并且该路径可用于存储文件。如果目标不存在,Test-Path
在这种情况下不会关心 - 它只被要求测试提供的路径是否可能有效。
答案 7 :(得分:0)
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;
}
}
}
答案 8 :(得分:0)
我最终遇到了这段代码。我需要稍后在脚本中创建一个文件,因此此代码假定您具有对目标文件夹的写访问权。
$File = ".\newdir\newfile.txt"
If (Test-Path $File) {
$Resolved = (Resolve-Path $File).Path
} else {
New-Item $File -ItemType File | Out-Null
$Resolved = (Resolve-Path $File).Path
Remove-Item $File
}
我也将New-Item
放在了try..catch
块中,但这没有这个问题。
答案 9 :(得分:0)
我有一个类似的问题,我需要从一个尚不存在的文件夹中向上找到3个文件夹,以确定要创建的新文件夹的名称。这很复杂。无论如何,这就是我最终要做的:
($path -split "\\" | select -SkipLast 3) -join "\\"
答案 10 :(得分:-1)
您可以将-errorAction设置为“SilentlyContinue”并使用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 >
答案 11 :(得分:-1)
两个最流行的答案在不存在的驱动器上的路径上均无法正常工作。
function NormalizePath($filename)
{
$filename += '\'
$filename = $filename -replace '\\(\.?\\)+','\'
while ($filename -match '\\([^\\.]|\.[^\\.]|\.\.[^\\])[^\\]*\\\.\.\\') {
$filename = $filename -replace '\\([^\\.]|\.[^\\.]|\.\.[^\\])[^\\]*\\\.\.\\','\'
}
return $filename.TrimEnd('\')
}
答案 12 :(得分:-2)
在解决之前检查文件是否存在:
if(Test-Path .\newdir\newfile.txt) { (Resolve-Path .\newdir\newfile.txt).Path }