How does `if (Test-Path ...)` actually work?

In PowerShell, the syntax for if looks like this:

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

Another syntax rule: for subexpressions, you need to use parentheses as follows:

  write-output (get-date) 

Thus, if these two rules were combined, I would expect that the test for some path should be written with two sets of parentheses, such as:

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

However, this also works:

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

and just for completeness, this one doesn't work :

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

(here you will need to copy the subexpression in brackets, as usual).

Can someone explain the syntax rules that apply here, and how is it that I can use the IF test with only one bracket? Is this some kind of PowerShell magic, or do I not understand the basic syntax rules?

+6
source share
2 answers

Referring to C.2.2 from Appendix C: PowerShell Grammar in Bruce Payette Windows PowerShell in action , we have:

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

This indicates tokens ( and ) as part of the literal syntax for recognizing the if and that the <test> of about_If refers to the pipeline, which will be resolved to the logical one.

Following the rules of the pipeline, we find:

  • Test-Path ... parses on <cmdletCall> of <name> <parameterArgumentToken> ,
  • !Test-Path ... derives <expressionRule> from <UnaryOperatorToken> <propertyOrArrayReferenceRule> , which fails when the cmdlet call cannot match a simple property or array rule, whereas
  • !(Test-Path ...) is able to match the cmdlet call in parentheses as a subexpression.

Edit: See also PowerShell 2.0 Language Specification (thanks to Roman, he will answer another question ).

+3
source

The brackets after if define a subexpression (if parentheses were needed around Test-Path , then we would need parsers around $num -eq 5 and any other expression). Additional brackets after the not operator are required because Test-Path must be evaluated before it can be undone. You can try this without an if statement.

This does not work:

 PS> !Test-Path NonExistent.file 

It works:

 PS> !(Test-Path NonExistent.file) 
+3
source

Source: https://habr.com/ru/post/913032/


All Articles