powershell System.IO.FileInfo和相对路径

pgx2nnw8  于 2022-11-10  发布在  Shell
关注(0)|答案(3)|浏览(177)

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

示例

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

编辑

为了澄清这一点,System.IO.FileInfo在Windows或Linux上处理相对路径的方式没有区别。此问题与Push-LocationSet-Location未更新[System.IO.Directory]::GetCurrentDirectory()有关。
一个简单的例子:

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
}
72qzrwbm

72qzrwbm1#

感觉有点重复,但既然你问了..
对不起,我对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**。
看来,您需要首先检查操作系统,然后在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))
        }
    }
}
plicqrtu

plicqrtu2#

另一种选择:
正如您希望转换为[System.IO.FileInfo]的结果一样,您可以改用Get-Item,它也将返回一个[System.IO.FileInfo]对象,但具有已解析的相对路径*正如预期的那样。它还将包含一些错误检测(无效字符或不存在的路径等)。
示例:

PS C:\Users\User\Documents> (Get-Item -LiteralPath '.\test.txt').FullName
C:\Users\User\Documents\test.txt
zysjyyx4

zysjyyx43#

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

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

如果我们使用[cmdletbinding()],另一个很好的选择是使用$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

相关问题