about_Parsing

简短说明

描述 PowerShell 如何分析命令。

长说明

在命令提示符下输入命令时,PowerShell 将命令文本分解为一系列称为 令牌 的段,然后确定如何解释每个标记。

例如,如果键入:

Write-Host book

PowerShell 将命令分解为两个标记 Write-Hostbook,并使用两种主要分析模式之一(表达式模式和参数模式)独立解释每个标记。

注意

当 PowerShell 分析命令输入时,它会尝试将命令名称解析为 cmdlet 或本机可执行文件。 如果命令名称没有完全匹配,PowerShell 会将 Get- 命令作为默认谓词追加到命令前面。 例如,PowerShell 分析 ProcessGet-Process。 出于以下原因,不建议使用此功能:

  • 效率低下。 这会导致 PowerShell 多次搜索。
  • 首先解析同名的外部程序,因此可能不会执行预期的 cmdlet。
  • Get-HelpGet-Command 不识别无动词名称。

表达式模式

表达式模式用于组合表达式,这些表达式是脚本语言的值操作所必需的。 表达式是 PowerShell 语法中值的表示形式,可以是简单或复合的,例如:

文本表达式是其值的直接表示形式:

'hello'
32

变量表达式携带它们引用的变量的值:

$x
$script:path

运算符结合其他表达式进行求值:

-12
-not $Quiet
3 + 7
$input.Length -gt 1
  • 字符串文本 必须包含在引号中。
  • 除非 (转义) ,否则数字被视为数值而不是一系列字符。
  • 运算符(包括 一元运算符(如 --not )和 二元运算符(如 +-gt)被解释为运算符,并对其参数 (操作数) 应用各自的运算。
  • 属性和转换表达式 分析为表达式,并应用于从属表达式,例如 [int] '7'
  • 变量引用 将计算为其值,但 ( 即禁止粘贴预填充参数集) 并导致分析程序错误。
  • 任何其他内容都将视为要调用的命令。

参数模式

分析时,PowerShell 首先将输入解释为表达式。 但是,当遇到命令调用时,分析将继续在参数模式下进行。 如果你有包含空格的参数(如路径),则必须将这些参数值括在引号中。

参数模式设计用于分析 shell 环境中的命令的参数和参数。 所有输入都被视为可展开字符串,除非它使用以下语法之一:

  • 美元符号 ($) 后跟变量名称开始一个变量引用,否则,它将解释为可展开字符串的一部分。 变量引用可以包括成员访问或索引。

    • 简单变量引用之后的其他字符(如 $HOME)被视为同一参数的一部分。 将变量名称括在大括号 ({}) ,以将其与后续字符分隔开。 例如 ${HOME}
    • 当变量引用包含成员访问时,任何其他字符中的第一个被视为新参数的开头。 例如 $HOME.Length-more ,生成两个参数:的值 $HOME.Length 和字符串文本 -more
  • 引号 ('") 开始字符串

  • 大括号 ({}) 开始新的脚本块

  • 逗号 (,) 引入作为数组传递的列表,除非要调用的命令是本机应用程序,在这种情况下,它们被解释为可扩展字符串的一部分。 不支持初始、连续或尾随逗号。

  • 括号 (()) 开始新表达式

  • Subexpression 运算符 ($()) 开始嵌入表达式

  • 初始 at 符号 (@) 开始表达式语法,例如 () @args 、数组 () @(1,2,3) 和哈希表文本 (@{a=1;b=2}) 。

  • ()$()@() 在令牌开头创建可以包含表达式或嵌套命令的新分析上下文。

    • 当后跟其他字符时,第一个附加字符被视为新的独立参数的开头。
    • 当前面有无引号文本$()时,其工作原理类似于可展开的字符串,()启动一个表达式的新参数,并@()作为文本@()来启动作为表达式的新参数。
  • 其他所有内容都被视为可展开的字符串,但仍然需要转义的元字符除外。

    • 参数模式元字符 (具有特殊语法含义的字符) 为: <space> ' " ` , ; ( ) { } | & < > @ #。 其中, < > @ # 仅在令牌的开头是特殊的。
  • 停止分析标记 (--%) 更改所有剩余参数的解释。 有关详细信息,请参阅下面的 停止分析令牌 部分。

示例

下表提供了在表达式模式和参数模式下处理的标记的几个示例,以及这些标记的计算。 对于这些示例,变量$a4的值为 。

示例 模型 结果
2 表达式 2 (整数)
`2 Expression “2” (命令)
Write-Output 2 Expression 2 (整数)
2+2 Expression 4 (整数)
Write-Output 2+2 参数 “2+2” (字符串)
Write-Output(2+2) Expression 4 (整数)
$a Expression 4 (整数)
Write-Output $a Expression 4 (整数)
$a+2 Expression 6 (整数)
Write-Output $a+2 参数 “4+2” (字符串)
$- 参数 “$-” (命令)
Write-Output $- 参数 “$-” (字符串)
a$a Expression “a$a” (命令)
Write-Output a$a 参数 “a4” (字符串)
a'$a' Expression “a$a” (命令)
Write-Output a'$a' 参数 “a$a” (字符串)
a"$a" Expression “a$a” (命令)
Write-Output a"$a" 参数 “a4” (字符串)
a$(2) Expression “a$ (2) ” (命令)
Write-Output a$(2) 参数 “a2” (字符串)

每个标记都可以解释为某种对象类型,例如 布尔 值或 字符串。 PowerShell 尝试从表达式中确定对象类型。 对象类型取决于命令所需的参数类型以及 PowerShell 是否知道如何将参数转换为正确的类型。 下表显示了分配给表达式返回的值的几个类型示例。

示例 模型 结果
Write-Output !1 参数 “!1” (字符串)
Write-Output (!1) 表达式 假 (布尔)
Write-Output (2) 表达式 2 (整数)
Set-Variable AB A,B 参数 “A”、“B” (数组)
CMD /CECHO A,B 参数 “A,B” (字符串)
CMD /CECHO $AB 表达式 “A B” (数组)
CMD /CECHO :$AB 参数 “:A B” (字符串)

将自变量传递到本机命令

从 PowerShell 运行本机命令时,首先由 PowerShell 分析参数。 然后,将分析的参数联接到单个字符串中,每个参数用空格分隔。

例如,以下命令调用 icacls.exe 程序。

icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

若要在 PowerShell 2.0 中运行此命令,必须使用转义字符来防止 PowerShell 错误解释括号。

icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F

停止分析令牌

从 PowerShell 3.0 开始,可以使用 停止分析 (--%) 令牌来阻止 PowerShell 将输入解释为 PowerShell 命令或表达式。

注意

停止分析令牌仅适用于 Windows 平台。

调用本机命令时,将停止分析令牌放在程序参数之前。 此方法比使用转义字符来防止错误解释要容易得多。

遇到停止分析令牌时,PowerShell 会将行中的剩余字符视为文本。 它执行的唯一解释是将值替换为使用标准 Windows 表示法的环境变量,例如 %USERPROFILE%

icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F

PowerShell 将以下命令字符串发送到 icacls.exe 程序:

X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

停止分析令牌仅在下一个换行符或管道字符之前有效。 不能使用延续字符 (`) 来扩展其效果,也不能使用命令分隔符 (;) 终止其效果。

除环境变量引用外 %variable% ,不能在命令中嵌入任何其他动态元素。 %不支持将字符转义为 %%,即在批处理文件中执行的操作。 %<name>% 令牌总是扩展的。 如果未 <name> 引用定义的环境变量,则令牌将按原样传递。

不能像) 一样 >file.txt 使用流重定向 (,因为它们作为参数逐字传递给目标命令。

传递包含引号字符的参数

某些本机命令需要包含引号字符的参数。 通常,PowerShell 的命令行分析会删除你提供的引号字符。 然后,将分析的参数联接到单个字符串中,每个参数用空格分隔。 然后,将此字符串分配给 对象的 Arguments 属性 ProcessStartInfo 。 字符串中的引号必须使用额外的引号或反斜杠 (\) 字符进行转义。

注意

PowerShell 无法将反斜杠 (\) 字符识别为转义字符。 它是 的基础 API 使用的 ProcessStartInfo.Arguments转义字符。

有关转义要求的详细信息,请参阅 ProcessStartInfo.Arguments 的文档

以下示例使用 TestExe.exe 工具。 此工具由 PowerShell 源存储库中的 Pester 测试使用。 这些示例的目标是将目录路径 "C:\Program Files (x86)\Microsoft\" 传递给本机命令,以便它接收带引号的字符串形式的路径。

echoargs 参数 TestExe 将接收的值显示为可执行文件的参数。 可以使用此工具验证是否已正确转义参数中的字符。

TestExe -echoargs """""${env:ProgramFiles(x86)}\Microsoft\\"""""
TestExe -echoargs """""C:\Program Files (x86)\Microsoft\\"""""
TestExe -echoargs "\""C:\Program Files (x86)\Microsoft\\"""
TestExe -echoargs --% "\"C:\Program Files (x86)\Microsoft\\"
TestExe -echoargs --% """C:\Program Files (x86)\Microsoft\\""
TestExe -echoargs --% """%ProgramFiles(x86)%\Microsoft\\""

所有示例的输出都相同:

Arg 0 is <"C:\Program Files (x86)\Microsoft\">

可从源代码生成 TestExe。 请参阅 TestExe

将参数传递给 PowerShell 命令

从 PowerShell 3.0 开始,可以使用 参数结束 标记 (--) 来阻止 PowerShell 将输入解释为 PowerShell 参数。 这是 POSIX Shell 和实用工具规范中指定的约定。

参数结束标记 (--) 指示其后面的所有参数都将以实际形式传递,就像在它们周围放置双引号一样。 例如,使用 -- 可以输出字符串 -InputObject ,而无需使用引号或将其解释为参数:

Write-Output -- -InputObject
-InputObject

与停止分析 (--%) 令牌不同,标记后 -- 的任何值都可以由 PowerShell 解释为表达式。

Write-Output -- -InputObject $env:PROCESSOR_ARCHITECTURE
-InputObject
AMD64

此行为仅适用于 PowerShell 命令。 如果在调用外部命令时使用该 -- 令牌,字符串 -- 将作为参数传递给该命令。

TestExe -echoargs -a -b -- -c

输出显示 -- 作为参数传递给 TestExe的 。

Arg 0 is <-a>
Arg 1 is <-b>
Arg 2 is <-->
Arg 3 is <-c>

另请参阅