System.IO.FileInfo 和相对路径
System.IO.FileInfo and Relative Paths
我想知道是否有人可以帮助我理解为什么 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 上的相对路径没有区别。该问题与 [System.IO.Directory]::GetCurrentDirectory()
未被 Push-Location
或 Set-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
我想知道是否有人可以帮助我理解为什么 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 上的相对路径没有区别。该问题与 [System.IO.Directory]::GetCurrentDirectory()
未被 Push-Location
或 Set-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