mkl*_*nt0 20 syntax powershell parameter-passing command-line-parsing
注意:此问题的摘要已在PowerShell GitHub存储库中发布,因为已被此更全面的问题所取代.
传递给PowerShell中的命令的参数在参数模式下进行解析(与表达式模式相反- 请参阅参考资料Get-Help about_Parsing).
方便地,(双)引用不包含空格或元字符的参数通常是可选的,即使这些参数涉及变量引用(例如$HOME\sub)或子表达式(例如,version=$($PsVersionTable.PsVersion).
在大多数情况下,这些不带引号的参数被视为双引号字符串,并且通常的字符串插值规则适用(除了元字符,例如,需要转义).
我试图在这个答案中总结参数模式中未加引号的标记的解析规则,但是有一些奇怪的边缘情况:
具体来说(从Windows PowerShell v5.1开始),为什么以下每个命令中的未加引号的参数标记不被识别为单个可扩展字符串,并导致传递2个参数(变量reference/subexpression保留其类型) ?
$(...)在令牌的开头:
Write-Output $(Get-Date)/today # -> 2 arguments: [datetime] obj. and string '/today'
Run Code Online (Sandbox Code Playgroud)
请注意,以下工作符合预期:
Write-Output $HOME/sub - 简单的var.一开始就参考Write-Output today/$(Get-Date) - 子表达式不是一开始.$在令牌的开头:
Write-Output .$HOME # -> 2 arguments: string '.' and value of $HOME
Run Code Online (Sandbox Code Playgroud)
请注意,以下工作符合预期:
Write-Output /$HOME - 不同的初始字符.前$Write-Output .-$HOME- 最初.没有直接跟着$Write-Output a.$HOME- .不是最初的char.暂且不说:从PowerShell Core v6.0.0-alpha.15开始,=下面是一个简单的var.令牌开头的引用似乎也将令牌分成2个参数,这在Windows PowerShell v5.1 中不会发生; 例如,.Write-Output $HOME=dir
注意:
我主要是为所描述的行为寻找设计原理,或者视情况而定,确认它是一个错误.如果它不是一个错误,我想要一些东西帮助我概念化行为,所以我可以记住它并避免它的陷阱.
所有这些边缘情况都可以通过显式双引用来避免,考虑到上面的非显而易见的行为,这可能是常规使用的最安全的选择.
在撰写本文时,v5.1 Get-Help about_Parsing页面:
不完整地描述了规则
使用在PowerShell世界中既未在主题中定义也未普遍使用的术语("可扩展字符串","值表达式" - 尽管可以猜出它们的含义)
从链接页面(重点添加):
在参数模式下,每个值都被视为可扩展字符串, 除非它以下列特殊字符之一开头:美元符号(
$),符号(@),单引号('),双引号(")或左括号(().如果前面有其中一个字符,则将该值视为值表达式.
顺便说一下:开头的标记"当然是定义,也是一个可扩展的字符串(插值字符串).
奇怪的是,关于引用的概念性帮助主题Get-Help about_Quoting_Rules,设法避免术语"扩展"和"插入".
请注意该段落并未说明当(非元)字符直接跟随以这些特殊字符开头的标记时会发生什么,特别是$.
但是,该页面包含一个示例,该示例显示以变量引用开头的标记也被解释为可扩展字符串:
$acontains 4,Write-Output $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'
Run Code Online (Sandbox Code Playgroud)
为什么不应该Write-Output $(2 + 2)/H扩展到'4/H'(而不是被视为2个参数?
为什么一开始的子表达式与变量引用的处理方式不同?
这种微妙的区别很难记住,特别是在没有正当理由的情况下.
对我来说更有意义的规则是无条件地处理以变量reference/subexpression作为可扩展字符串开头$ 并且具有附加字符的标记.
(相比之下,独立变量引用/子表达式保留其类型是有意义的,就像现在一样.)
请注意,.$完全没有在帮助主题中介绍以分割为2个参数开头的标记的情况.
在其他特殊的令牌启动字符中,以下无条件地将构造结尾后面的任何字符视为单独的参数(这是有意义的):
( ' "
Write-Output (2 + 2)/H # -> 2 arguments: 4 and '/H'
Write-Output "2 + $a"/H # -> 2 arguments: '2 + 4' and '/H', assuming $a equals 4
Write-Output '2 + 2'/H # -> 2 arguments: '2 + 2' and '/H'
Run Code Online (Sandbox Code Playgroud)
bash顺便说一句:这表明- 样式字符串连接 - 将引用和非引用令牌的任意组合放在一起 - PowerShell通常不支持; 它只有当工作第1子/变量引用恰好是加引号.例如Write-Output H/'2 + 2',不同于上述的子串反转例如,只产生单个的参数.
例外情况是@:虽然后面只有一个语法上有效的变量名称(例如),但@确实具有特殊含义(请参阅Get-Help about_Splatting),其他任何原因都会导致令牌再次被视为可扩展字符串:@parms
Write-Output @parms # splatting (results in no arguments if $parms is undefined)
Write-Output @parms$a # *expandable string*: '@parms4', if $a equals 4
Run Code Online (Sandbox Code Playgroud)
我认为你在这里所说的更多的是“暗示”类型,而不是其他任何东西。
您正在使用 Write-Output,它在概要中指定它
将指定对象发送到管道中的下一个命令。
该命令旨在接收数组。当它像今天一样以字符串形式命中第一个项目时,它会将其视为字符串。当第一项最终成为函数调用的结果时,它可能是也可能不是字符串,因此它会启动一个数组。
这表明,如果您对 Write-Host 运行相同的命令(旨在接收要输出的字符串),它会按照您的预期工作:
Write-Host $(Get-Date)/today
Run Code Online (Sandbox Code Playgroud)
输出
2018 年 7 月 25 日下午 1:30:43 /今天
所以我认为你遇到的边缘情况与解析无关,而与 powershell 使用(并试图隐藏)的类型有关。
| 归档时间: |
|
| 查看次数: |
535 次 |
| 最近记录: |