2

我今天在 Powershell 5.1 中使用选项卡自动完成作为变量名,并注意到其中一个选项是 PSDrive 的名称。驱动器名称是docs,我想扩展的是$document_name. 当我输入$do<tab>时,shell 确实扩展了我输入的内容,$document_name但由于某种原因,我再次输入<tab>了第二次,这时扩展的文本变为$docs:.

我进一步探索并发现我的每个 PSDrives 都存在这种类型的变量,或者至少选项卡扩展表明它确实存在。

更正式地说,对于每个 PSDrive PSD,选项卡扩展认为这$PSD:是一个有效的事情。

我的问题很简单:这些到底是什么?以下是我到目前为止所做的一些观察:

  • 这些名称以 为前缀$,因此它们看起来像 PS 变量。对于本次讨论的其余部分(以及在前面的讨论中),我将假设它们是变量并这样引用它们。
  • 尽管它们看起来是变量,但它们并没有Variable:像大多数变量一样在 PSDrive 中列出。这样,它的行为就像$env“变量”,也没有在Variable:. 我有一种感觉,如果我能找到关于 的文档$env,那么我也会理解这些对象。
  • 在某些方面,它们的行为类似于指向文件系统对象的指针。例如,如果有一个readme.txt包含文本“Hello, world!”的文件名。在名为 的 PSDrive 上code,则以下所有内容都是与 Powershell 的可能交互。

获取文件的内容。

λ  ${code:\readme.txt}
Hello, world!

只是为了证明上述结果的类型是String

λ  ${code:\readme.txt} | % { $_.GetType().Name }
String

尝试将其用作对 PSDrive 的引用对于许多操作都不起作用,例如cd

C:\
λ  cd ${code:}
At line:1 char:4
+ cd ${code:}
+    ~~~~~~~~
Variable reference is not valid. The variable name is missing.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvalidBracedVariableReference

我可以继续,但我很难过。如果我通过$code:(或者$env:,就此而言)到Get-Member,我会收到一个错误消息Variable reference is not valid

那么到底什么是“变量”$env$<PSDrive>:(例如$code:)?它们是表达式吗?内置表达式?某种对象?谢谢你的帮助。

4

2 回答 2

3

您所看到的是命名空间变量表示法,这是一种基于变量的方式来访问 PowerShell 驱动器中的项目内容,其底层提供程序实现了基于内容的访问(即,实现了IContentCmdletProvider接口)。

一般语法是:

${<drive>:<path>}       # same as: Get-Content <drive>:<path>

${<drive>:<path>} = ... # same as: Set-Content <drive>:<path> -Value ...

如果name 和can 在语法上都用作变量名,{...}则不需要封闭;例如:<drive><path>

$env:HOME  # no {...} needed

${env:ProgramFiles(x86)} # {...} needed due to "(" and ")"

实际上,从 Windows PowerShell v5.1 开始,以下内置驱动器提供程序支持命名空间变量表示法

  • 环境(驱动器Env:
  • 功能(驱动Function:
  • 别名(驱动器Alias:
  • 文件系统(驱动器C:,...)
  • 变量 (drive Variable:) - 虽然实际上没有意义,但忽略驱动器部分会默认访问变量(例如,$variable:HOME与 just 相同$HOME)。

其中,Env:驱动器是迄今为止最常使用命名空间变量表示法的驱动器,尽管大多数用户不知道环境变量引用(例如$env:HOME.

有时您会看到它与文件系统驱动器一起使用 - 例如${c:\foo\file.txt}- 但您只能使用文字路径并且您无法控制字符编码的事实限制了它的用途。

但是,它允许有趣的用途;例如:

PS> $alias:foreach  # Get the definition of alias 'foreach'
ForEach-Object

PS> $function:prompt # Get the body of the 'prompt' function
"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) ";
# .Link
# https://go.microsoft.com/fwlink/?LinkID=225750
# .ExternalHelp System.Management.Automation.dll-help.xml

# Define a function foo that echoes 'hi' and invoke it.
PS> $function:foo = { 'hi' }; foo
hi

笔记:

  • 因为${<drive>:<path>}and${<drive>:<path>} = <value>等同于
    Get-Content -Path <drive>:<path>and Set-Content -Path <drive>:<path> <value>,所以路径被解释为通配符表达式(因为这就是通配符表达式-Path,而不是-LiteralPath),这可能会导致看起来像通配符的路径出现问题 - 请参阅此答案以获取示例和解决方法。

  • 在撰写本文时,命名空间变量表示法尚未正式记录,但此 GitHub 问题建议这样做。

于 2019-03-07T05:13:34.150 回答
1

$env是 Windows 环境变量,与您SET在命令提示符下执行的操作相同。有一些是特定于 PS 的。

该变量提供对 Environment Provider 的访问。https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-6

这里描述了许多其他提供程序:https ://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_providers?view=powershell-6

正如doco中所说:

数据表示的模型是文件系统驱动器。要使用提供者公开的数据,您可以查看、移动并更改它,就像它是硬盘驱动器上的数据一样。因此,有关提供程序的最重要信息是它支持的驱动器的名称。

于 2019-03-07T01:33:46.743 回答