Powershell 参数模式中包含变量引用和子表达式的无引号标记:为什么它们有时会拆分为多个参数?

Powershell 参数模式中包含变量引用和子表达式的无引号标记:为什么它们有时会拆分为多个参数?,powershell,syntax,parameter-passing,command-line-arguments,Powershell,Syntax,Parameter Passing,Command Line Arguments,注:该问题的摘要已由取代 在PowerShell中传递给命令的参数在参数模式下解析(与表达式模式相反-请参阅) 方便地说,(双)引用不包含空格或元字符的参数通常是可选的,即使这些参数涉及变量引用(例如$HOME\sub)或子表达式(例如,版本=$($PsVersionTable.PsVersion)) 在大多数情况下,这类不带引号的参数被视为双引号字符串,并且通常适用(除了,等元字符需要转义) 我试图在中总结参数模式下无引号标记的解析规则,但有一些奇怪的边缘情况: 具体地说(从Windows P

注:该问题的摘要已由取代

在PowerShell中传递给命令的参数在参数模式下解析(与表达式模式相反-请参阅)

方便地说,(双)引用不包含空格或元字符的参数通常是可选的,即使这些参数涉及变量引用(例如
$HOME\sub
)或子表达式(例如,
版本=$($PsVersionTable.PsVersion)

在大多数情况下,这类不带引号的参数被视为双引号字符串,并且通常适用(除了
等元字符需要转义)

我试图在中总结参数模式下无引号标记的解析规则,但有一些奇怪的边缘情况

具体地说(从Windows PowerShell v5.1开始),为什么以下每个命令中的不带引号的参数标记不能识别为单个可扩展字符串,并导致传递2个参数(变量引用/子表达式保留其类型)

  • $(…)
    在令牌的开头:

    Write-Output $(Get-Date)/today # -> 2 arguments: [datetime] obj. and string '/today'
    
    Write-Output .$HOME  # -> 2 arguments: string '.' and value of $HOME
    
    • 请注意,应按预期完成以下工作:

      • 写入输出$HOME/sub
        -开始时的简单变量参考
      • 今天写入输出/$(获取日期)
        -子表达式不在开始处
  • $
    在令牌的开头:

    Write-Output $(Get-Date)/today # -> 2 arguments: [datetime] obj. and string '/today'
    
    Write-Output .$HOME  # -> 2 arguments: string '.' and value of $HOME
    
    • 请注意,应按预期完成以下工作:

      • Write Output/$HOME
        -不同的初始字符。前面的
        $
      • 写入输出。-$HOME
        -首字母
        不直接后跟
        $
      • 写入输出a.$HOME
        -
        不是初始字符
顺便提一下:从PowerShell Core v6.0.0-alpha.15开始,令牌开头的简单变量引用后面的
=
似乎也会将令牌分成两个参数,这在Windows PowerShell v5.1中不会发生;例如,
写入输出$HOME=dir

注:

  • 我主要是为所描述的行为寻找一个设计原理,或者,视情况而定,确认它是一个bug。如果它不是bug,我想要一些东西来帮助我概念化行为,这样我就可以记住它并避免它的陷阱

  • 所有这些边缘情况都可以通过明确的双引号避免,鉴于上述不明显的行为,这可能是常规使用的最安全的选择。


可选阅读:文档和设计构思的状态 截至撰写本文之时,该公司:

  • 不完整地描述规则

  • 使用的术语既没有在本主题中定义,也没有在PowerShell世界中普遍使用(“可扩展字符串”、“值表达式”-尽管可以猜测其含义)

从链接页面(添加了强调):

在参数模式下,每个值都被视为可扩展字符串,除非它以下列特殊字符之一开头:美元符号(
$
)、at符号(
@
)、单引号(
)、双引号(
)或开括号(

如果前面有这些字符之一,则该值将被视为值表达式

顺便提一下:根据定义,以“
”开头的标记也是一个可扩展字符串(插入字符串)。
奇怪的是,关于引用的概念性帮助主题设法避免了术语“扩展”和“插入”

请注意,当(非元)字符直接跟在以这些特殊字符开头的标记后面时,本文没有说明会发生什么,尤其是
$

但是,该页面包含一个示例,该示例显示以变量引用开头的标记也被解释为可扩展字符串:

  • $a
    包含
    4
    时,
    写入输出$a/H
    计算结果为(单字符串参数)
    4/H
请注意,这段文字确实暗示了未加引号的标记(不以特殊字符开头)内部的变量引用/子表达式被展开,就像在双引号字符串中一样(“被视为可展开字符串”)

如果这些措施奏效:

$a = 4
Write-Output $a/H         # -> '4/H'
Write-Output H/$a         # -> 'H/4'
Write-Output H/$(2 + 2)   # -> 'H/4'
为什么
Write Output$(2+2)/H
不应该也扩展到
'4/H'
(而不是被视为两个参数?
为什么子表达式在开始时的处理方式与变量引用不同

这样微妙的区别很难记住,尤其是在没有正当理由的情况下

对我来说更有意义的规则是无条件地将以
$
开头并在变量引用/子表达式后面有附加字符的标记视为可扩展字符串。

(相比之下,独立变量引用/子表达式保留其类型是有意义的,就像现在一样。)


请注意,以
$
开头的标记被拆分为两个参数的情况在帮助主题中根本没有介绍


更可选的读取:跟随以其他特殊字符之一开头的标记,并添加其他字符。 在其他特殊标记起始字符中,以下命令无条件地将构造结尾后的任何字符作为单独的参数处理(这很有意义):
(“

顺便说一句:这显示了
bash
样式的字符串连接-
 Write-Host $(Get-Date)/today