powershell - Windows $env:path ="$($env:path);." 它是在哪里添加的?
问题描述
$env:path ="$($env:path);."
我通过从 PowerShell运行“修复”了一个问题。显然它将当前目录添加到我的路径中。请问它添加了哪个路径变量?在我的环境变量对话中,我会在哪里看到它添加?用户变量?系统变量?
我很困惑,因为我已经将文件夹添加到系统变量path
中,但是在运行 ``$env:path ="$($env:path);." 之前无法运行包含的脚本。
解决方案
$env:EnvVarName
仅影响当前进程的更新- 不会通过注册表进行持久更改:
$env:EnvVarName = 'foo'
相当于调用 .NET 方法System.Environment.SetEnvironmentVariable
,如下所示:
[Environment]::SetEnvironmentVariable('EnvVarName', 'foo', 'Process')
即更新的范围是当前进程。
仅当您在上述调用中替换'User'
或'Machine'
替换(仅在 Windows [1]上受支持)时,您才会持续更新注册表中的环境变量'Process'
(分别针对当前用户或本地计算机(所有用户)),以用于将来的会话(进程) [2]。
从 PowerShell [Core] 7.2 开始,没有PowerShell 原生方式来持续更新环境变量,但在 GitHub 上正在讨论引入一种方式。
换句话说:如果您不仅要更新基于注册表的定义,还要更新当前进程中的值,则需要进行两次调用;例如,对于当前用户:
# Windows only: Update / create a persistent definition for the current user,
# stored in the registry.
[Environment]::SetEnvironmentVariable('EnvVarName', 'foo', 'User')
# Update value for current process too.
$env:EnvVarName = 'foo'
或者,更符合DRY的精神:
'User', 'Process' | foreach {
[Environment]::SetEnvironmentVariable('EnvVarName', 'foo', $_)
}
如果新值基于给定注册表范围中的现有值,请通过System.Environment.GetEnvironmentVariable
;检索特定于范围的值 例如:
# Get the registry-based *user* value
[Environment]::GetEnvironmentVariable('Path', 'User')
警告:不支持基于 REG_EXPAND_SZ
注册表值的 Windows 环境变量:
在 Windows 上,可以基于其他环境变量定义持久定义的环境变量,即定义变量的底层注册表值是否为REG_EXPAND_SZ
.
从 .NET 6 开始,该System.Environment
类型的方法不(直接)支持此类环境变量:
在获得这样一个变量的值时,它的扩展形式总是被返回;也就是说,对其他环境变量的引用
%SystemRoot%
被它们的值替换。在设置环境变量时,总是会
REG_SZ
创建注册表值,即静态的逐字记录值——即使在更新现有值时也是如此。REG_EXPAND_SZ
虽然悄悄地将REG_EXPAND_SZ
环境变量转换为静态变量REG_SZ
通常不会产生不良影响(只要新值只包含文字值),它当然可以:例如,假设一个变量是根据%JAVADIR%
; 如果该变量基于 的当前值转换为静态值,则如果稍后更改%JAVADIR%
的值,它将停止工作。%JAVADIR%
不幸的是,目前检索原始REG_EXPAND_SZ
环境变量和正确更新它们的值需要直接访问注册表,这非常麻烦(甚至 Windows API 似乎都不支持它) - 请参阅此答案。
Windows 上Path
环境变量 ( )的重要注意事项:$env:PATH
环境变量的
Path
特殊之处在于它是一个复合值:当一个进程启动时,进程内值是(本地机器,对于所有用户)值和(当前用户)值的串联。Machine
User
- 请注意,由于机器级值首先出现,因此其条目优先于用户级值的条目。
因此,如果您想修改(附加到)现有
Path
的 ,最好不要简单地通过附加到现有的进程中值 ($env:Path
) 来定义新值,因为您将复制Machine
orUser
值,具体取决于您的范围目标。相反,有选择地从目标范围检索现有值,修改该值(通常通过附加目录,然后将修改后的值写回同一范围。
考虑到进程中的副本可能已被修改,要使相同的修改在当前进程中稳健地生效也很重要;
$env:Path
但是,在将新目录附加到用户路径的简单情况下,您可以简单地执行$env:Path += ';' + $newDir
; 在其他情况下,您也可以使用这种简单的方法,但请注意,考虑到列出目录的顺序$env:Path
很重要,行为可能会有所不同。
重要提示:默认情况下, Path
Windows 上的环境变量是REG_EXPAND_SZ
基于 - 的,因此需要注意REG_SZ
以下代码执行的静默转换为基于静态的值 - 再次,请参阅此答案以获得正确但更复杂的解决方案。
例子:
# New dir. to add to the *user's* path
$newDir = 'c:\foo\bin'
# Get current value *from the registry*
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
# Append the new dir and save back to the registry.
[Environment]::SetEnvironmentVariable('Path', ($userPath + ';' + $newDir), 'User')
# To also update the current process, append $newDir to the in-process
# variable, $env:Path
$env:Path += ';' + $newDir
顺便说一句:在类 Unix 平台上,分隔符是:
,而不是;
( 反映在 中[System.IO.Path]::PathSeparator
,区分大小写的变量名是Path
。如上所述,.NET 从根本上不提供类 Unix 平台上的持久环境变量定义(如.NET Core 3.1),因为各种平台没有统一的本地机制来执行此操作。
[1] 在类 Unix 平台上,从 .NET Core 3.1 开始,定位或被User
悄悄忽略Machine
[2]警告:由当前 PowerShell 会话(直接调用、、)直接创建的新进程Start-Process
尚未Start-Job
看到注册表更改,因为它继承了当前会话的环境。
推荐阅读
- python - Python:如何使用函数调用来切换大小写以进行 Pygame 显示
- material-ui - 使用tab键时如何在Material UI Table中的TableSortLabel中添加按钮等波纹效果
- google-sheets - 如何将 minifs 与 arrayformula 一起使用,以便自动填充整个列?
- node.js - 如何仅使用 TSC 正确导出 typescript 库以用于 react 和 node
- javascript - 可以使用 JS 或 PHP 创建操作系统吗
- python - 没有这样的文件或目录
- php - laravel广播redis socket-io,不监听事件
- android - android:fitsSystemWindows="true" 采用原色而不是半透明
- time - 如何在特定时间发送警报
- java - java.lang.ClassNotFoundException: javax.validation.Validation