Powershell 中的 $<drivename>:(例如 `$code:`)是什么类型的对象?

chr*_*ris 2 powershell namespaces powershell-v5.1 new-psdrive

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

\n\n

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

\n\n

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

\n\n

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

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

获取文件的内容。

\n\n
\xce\xbb  ${code:\\readme.txt}\nHello, world!\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
\xce\xbb  ${code:\\readme.txt} | % { $_.GetType().Name }\nString\n
Run Code Online (Sandbox Code Playgroud)\n\n

尝试使用它作为对 PSDrive 的引用对于许多操作来说效果不佳,例如cd

\n\n
C:\\\n\xce\xbb  cd ${code:}\nAt line:1 char:4\n+ cd ${code:}\n+    ~~~~~~~~\nVariable reference is not valid. The variable name is missing.\n    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException\n    + FullyQualifiedErrorId : InvalidBracedVariableReference\n
Run Code Online (Sandbox Code Playgroud)\n\n

我可以继续说下去,但我被难住了。如果我传递$code:(或$env:就此而言)到Get-Member,我会收到一条错误消息Variable reference is not valid: 。

\n\n

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

\n

mkl*_*nt0 6

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

术语和文档说明

  • 截至撰写本文时,文档在概念性about_Scopes帮助主题中简要解释了命名空间变量表示法,尽管没有使用该术语,并且在作用域修饰符的上下文中讨论它,这有点令人困惑;虽然命名空间限定符(例如)与作用域修饰符(例如)无关,但它们使用相同的基本语法形式。[1]$env:$script:

一般语法是:

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

${<drive>:<path>} = ... # same as: Set-Content <drive>:<path> -Value ...
Run Code Online (Sandbox Code Playgroud)

如果名称和 the在语法上都可以用作变量名称,则{...}不需要括起来;例如:<drive><path>

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

${env:ProgramFiles(x86)} # {...} needed due to "(" and ")"
Run Code Online (Sandbox Code Playgroud)

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

  • 环境(驱动器Env:
  • 功能(驱动Function:
  • 别名(驱动器Alias:
  • 文件系统(驱动器C:,...)
  • 变量 (drive Variable:) - 尽管实际上毫无意义,因为省略drive 部分默认会访问变量(例如,$variable:HOME与只是相同$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
Run Code Online (Sandbox Code Playgroud)

笔记:

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

[1] 以前,该功能根本没有记录;GitHub 文档问题 #3343导致了当前文档,尽管不是以所述问题提出的方式。