System.IO.FileInfo 和相对路径

System.IO.FileInfo and Relative Paths

我想知道是否有人可以帮助我理解为什么 System.IO.FileInfo 在处理相对路径时在 Windows 上的行为与在 Linux 上的行为不同。

例子

PS /home/user/Documents> ([System.IO.FileInfo]'./test.txt').FullName
/home/user/Documents/test.txt
PS C:\Users\User\Documents> ([System.IO.FileInfo]'.\test.txt').FullName
C:\Users\User\test.txt

编辑

为了澄清上述内容,System.IO.FileInfo 如何处理 Windows 或 Linux 上的相对路径没有区别。该问题与 [System.IO.Directory]::GetCurrentDirectory() 未被 Push-LocationSet-Location 更新有关。

一个简单的例子:

PS /home/user> [System.IO.Directory]::GetCurrentDirectory()
/home/user
PS /home/user> cd ./Documents/
PS /home/user/Documents> [System.IO.Directory]::GetCurrentDirectory()
/home/user

并且假设这是预期的行为,那么在脚本和函数上处理我们的 param(...) 块以接受两种情况(绝对和相对)的最佳方法是什么。我曾经将路径参数类型限制为 System.IO.FileInfo 但现在我可以看到它显然是错误的。

这是我遇到的,但我想知道是否有更好的方法。
我相信Split-Path -IsAbsolute如果使用网络路径也会带来问题,请指正我错了

param(
    [ValidateScript({ 
        if(Test-Path $_ -PathType Leaf) {
            return $true
        }
        throw 'Invalid File Path'
    })]
    [string]$Path
)

if(-not(Split-Path $Path -IsAbsolute)) {
    [string]$Path = Resolve-Path $Path
}

感觉有点重复,但既然你问了..

抱歉,我不知道 Linux,但在 Windows:

你可以先加个测试看看路径是不是相对路径,如果是就把它转成绝对路径如:

$Path = '.\test.txt'
if (![System.IO.Path]::IsPathRooted($Path) -or $Path -match '^\[^\]+') {
    $Path =  [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($pwd, $Path))
}

我添加了 $Path -match '^\[^\]+' 以转换以反斜杠开头的相对路径,如 \ReadWays.ps1 意味着路径从根目录开始。以两个反斜杠开头的 UNC 路径被视为绝对路径。


显然(我真的不知道为什么..)以上不适用于 Linux,因为在那里,当使用 UNC 路径时,部分 ![System.IO.Path]::IsPathRooted('\server\folder') 产生 True.

看来您需要先检查 OS 并在 Linux 上进行不同的检查。

$Path = '\server\share'

if ($IsWindows) {  # $IsWindows exists in version 7.x. Older versions do `$env:OS -match 'Windows'`
    if (![System.IO.Path]::IsPathRooted($Path) -or $Path -match '^\[^\]+') {
        $Path =  [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($pwd, $Path))
    }
}
else {
    if ($Path -notlike '\*\*') {  # exclude UNC paths as they are not relative
        if (![System.IO.Path]::IsPathRooted($Path) -or $Path -match '^\[^\]+') {
            $Path =  [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($pwd, $Path))
        }
    }
}

最简单的替代方法是使用 Convert-Path 来:

  • 处理 UNC、相对、绝对和根路径。
  • 兼容Windows和Linux
  • 高效

如果我们使用 [cmdletbinding()] is to use $PSCmdlet.GetUnresolvedProviderPathFromPSPath(..) method 的另一个巧妙的选择:

function ResolvePath {
    [cmdletbinding()]
    param($path)
    $PSCmdlet.GetUnresolvedProviderPathFromPSPath($path)
}

ResolvePath \server01\test         # => \server01\test
ResolvePath C:\Users\user\Documents # => C:\Users\user\Documents
ResolvePath C:Documents             # => C:\Documents
(ResolvePath .) -eq $PWD.Path       # => True
(ResolvePath ~) -eq $HOME           # => True