为什么`if(Test-Path ...)`实际上有效?

时间:2012-04-12 12:35:32

标签: powershell syntax

在PowerShell中,if语法如下:

if (<test1>)
    {<statement list 1>}
[elseif (<test2>)
    {<statement list 2>}]
[else
    {<statement list 3>}]

另一种语法规则是对于子表达式,你需要使用括号,如下所示:

 write-output (get-date)

因此,结合这两个规则,我希望某些路径的测试需要用两组括号写成:

if ((Test-Path ...)) {
    # do something
}

然而,这也有效:

if (Test-Path ...) {
    # do something
}

并且只是为了完整性,工作:

if (!Test-Path ...) {
    # do something
}

(这里,您需要像往常一样将子表达式包装在括号中)。

任何人都可以解释这里适用的语法规则吗?我怎么能只使用一个括号使用IF测试?它是一些PowerShell魔法还是我误解了基本的语法规则?

2 个答案:

答案 0 :(得分:4)

if之后的括号定义一个子表达式(如果Test-Path周围需要括号,那么我们需要围绕$num -eq 5和其他所有表达式的parens)..之后的附加括号因为Test-Path需要在被否定之前进行评估,所以不需要运算符。你可以在没有if语句的情况下尝试这个。

这不起作用:

PS> !Test-Path NonExistent.file

这确实有效:

PS> !(Test-Path NonExistent.file)

答案 1 :(得分:4)

参考Bruce Payette的Appendix C: The PowerShell grammar Windows PowerShell in Action中的C.2.2,我们有:

<ifStatementRule> =
  'if' '(' <pipelineRule> ')' <statementBlockRule>
  [ 'elseif' '(' <pipelineRule> ')' <statementBlockRule> ]*
  [ 'else' <statementBlockRule> ]{0|1}

这表示()令牌是用于识别if语句的文字语法的一部分,而<test>来自about_If文档指的是将被解析为布尔值的管道。

遵循管道规则,我们发现:

  • Test-Path ...解析为<cmdletCall> <name> <parameterArgumentToken>
  • !Test-Path ...会导致<expressionRule> <UnaryOperatorToken> <propertyOrArrayReferenceRule>,当cmdlet调用与简单属性或数组规则不匹配时会失败,而
  • !(Test-Path ...)能够将带括号的cmdlet调用与子表达式进行匹配。

修改:另请参阅PowerShell 2.0 Language Specification(感谢Roman's answer to another question)。