PowerShell 核心。相对路径问题

PowerShell Core. Relative path issue

PowerShell:

$file = "text.txt"
Test-Path $file            
# True
 
Get-Location
# C:\Users\Fors1k

[IO.File]::OpenRead($file) 
# FileStream
 
[IO.FileInfo]::new($file)  
# Mode                 LastWriteTime         Length Name                         
# ----                 -------------         ------ ----                         
# -a----        05.03.2021     18:12              7 text.txt  
                      
gc $file                   
# test123

一切正常。

PowerShell 核心:

$file = "text.txt"
Test-Path $file            
# True
 
Get-Location
# C:\Users\Fors1k

[IO.File]::OpenRead($file) 
# Exception calling "OpenRead" with "1" argument(s): "Could not find file 'C:\Windows\system32\text.txt'."
 
[IO.FileInfo]::new($file)  
# Mode                 LastWriteTime         Length Name                         
# ----                 -------------         ------ ----
# larhs          01.01.1601     3:00  
                      
gc $file                   
# test123

我这里有错误。

据我所知,问题是 .NET 方法认为当前位置是 sysfolder,而不是实际的当前位置。

回应建议:

我明白了,有很多解决办法:

$file = "text.txt"
[Environment]::CurrentDirectory = Get-Location
[IO.File]::OpenRead($file)
#
#
$file = "text.txt"
[IO.Directory]::SetCurrentDirectory((Get-Location))
[IO.File]::OpenRead($file)
#
#
$file = "text.txt"
$file = Convert-Path $file
[IO.File]::OpenRead($file)
#
#
# My solution, before asking, was
$file = "text.txt"
$file = Get-Item $file
[IO.File]::OpenRead($file)

但所有这些都是“随时随地修复”(我不知道这个短语的正确英语习语)。

我的意思是,为什么这在 posh 5.1 上正常工作?

为什么这段代码:[IO.File]::OpenRead("text.txt") 可以在 pwsh 上运行我的朋友,我问过哪些朋友?

可能还有这样的设置(夸张):[DotNet.Path]::SetDefaultLocation("TheSameAsPwsh")

@mathias-r-jessen,明白你的意思了:

[Environment]::CurrentDirectoryGet-Location 是一个最初无关的东西。

PowerShell:

"$(Get-Location)" -eq ([Environment]::CurrentDirectory)
# True
##
##
Set-Location ([Environment]::GetFolderPath("desktop"))

"$(Get-Location)" -eq ([Environment]::CurrentDirectory)
# False (!!!)

所以,我的问题是了解正在发生的事情:

为什么我的 pwsh 有 [Environment]::CurrentDirectory 作为 C:\Windows\system32,是否可以像在 posh 中一样将此 default 值更改为用户文件夹?

更改 .NET 的当前工作目录。

[Environment]::CurrentDirectory = "$(Get-Location)"

[System.IO.Directory]::SetCurrentDirectory("$(Get-Location)")

替代代码 - 结果相同
您的代码使用流。您应该 free/close 最后使用 try -finally.

流资源
$file = "text.txt"


if (! (Test-Path $file -PathType Leaf)) {
    New-Item $file
}

Get-Content $file

File.OpenRead(String path) Method
备注
path 参数允许指定相对或绝对路径信息。相对路径信息被解释为相对于当前工作目录。要获取当前工作目录,请参阅 GetCurrentDirectory.

Directory.GetCurrentDirectory Method
备注
当前目录与原始目录 distinct 不同,原始目录是启动进程的目录。

在 pwsh.exe 和 powershell.exe 中检查此方法。返回值不同。我认为每个都有不同的实现。

如果您 运行 来自脚本文件的代码。即 ./Script.ps1 您可以使用 $PSScriptroot 全局变量,它包含脚本所在目录的路径 运行ning.

Write-Host "ScriptPath: $PSScriptroot"
[Environment]::CurrentDirectory = "$PSScriptroot"
Write-Host "CurrentDirectory: $([Environment]::CurrentDirectory)"

在 PowerShell 中更改位置不会自动更新进程的工作目录 - 这是 .NET 用来在内部解析相对路径的内容。

作为,您可以通过在调用该方法之前更新[Environment]::CurrentDirectory来解决这个问题。

如果您发现自己在交互式使用 PowerShell 时经常 运行 遇到这个问题,请添加一种机制将其更新为 your prompt (the following example is lifted straight out of one of my own profile scripts) - 这将使两者保持“同步”:

$function:prompt = {
  if($PWD.Provider -eq 'FileSystem'){
    [Environment]::CurrentDirectory = $PWD.Path
  }

  "PS $($executionContext.SessionState.Path.CurrentLocation -replace [regex]::Escape($HOME),'~')$('>' * ($nestedPromptLevel + 1)) "
}