PowerShell是否要求脚本块的左大括号位于同一行?

时间:2017-10-31 01:01:46

标签: powershell syntax

好的,这个脚本的预期“输出”是相当明显的,它可以工作。它复制文件:

Get-ChildItem -Recurse -Directory | ForEach-Object{
    if ($_.Name.ToUpper().Contains("INCLUDE_PUBLIC")){
        Get-ChildItem -Recurse -File -Include "*.h" -Path $_.FullName | ForEach-Object {Copy-Item ($_.FullName) ("e:\IncTest")}
    }
}

但是,如果我将左大括号{移到下一行,我会得到以下输出:

cmdlet ForEach-Object at command pipeline position 2
Supply values for the following parameters:
Process[0]: 

我是否被其他语法问题所欺骗,或者ForEach-Object是否要求其括号位于同一行?

2 个答案:

答案 0 :(得分:4)

PowerShell有两种不同的解析模式,因为它既是 shell 又是脚本语言

  • 参数模式是面向行的,并且类似于shell :它适用于调用可执行文件/脚本的单个命令/ cmdlet / alias / function,或用管道符号(|)链接的一系列此类命令,以形成管道。

    • 每个单独的命令必须在其自己的行 ,并且将其分布在多行中的唯一方法是使用 line continuation ,这需要使用`(一个反引号)来逃避每条内线的末端 但是,这种做法在视觉上是微妙和脆弱的(在`打破命令后,甚至只放置空格或标签)。

    • 为了将管道的各个命令分散到多行(不必使用行继续),以|结束每一行但最后一行。

  • 表达式模式与其他编程语言中的一样,其中空格不重要:只要构造语法完整,可以跨越任意数量的行

重要的是要注意单个命令可能涉及 mix 解析模式,例如当您将脚本块传递给cmdlet时,cmdlet会解析它参数模式中的参数,但脚本块本身在表达式模式下解析(见下文)。

解析模式的官方文档在概念about_Parsing help topic

ForEach-Object cmdlet ,因此在参数模式中解析。

因此,除非你使用行继续,否则它不会在后续行上查找参数,并且在没有参数的情况下自行执行ForEach-Object会导致提示< / em>对于那些必需的参数 - -Process脚本块 - 这就是你所看到的。

相比之下,尽管脚本块在后续行中继续存在,... | ForEach-Object {仍可正常工作,因为脚本块本身在表达式模式下进行解析,允许它分布在多行中,而开始脚本块 - 开头{ - 与ForEach-Object位于同一行,足以让ForEach-Object识别出来。

对比 cmdlet ForEach-Object(在参数模式下解析)与foreach 语句进行对比的示例在表达模式 [1]

# Argument mode 
1, 2 | ForEach-Object { # opening brace must be on same line
  "Element: $_" 
}


# Expression mode
foreach ($el in 1, 2) # expression mode - OK to place opening { on next line
{
  "Element: $el" 
}

[1]请注意,也许令人困惑的是,ForEach-Object还有一个名为foreach别名,它模糊了cmdlet和{{1}之间的区别} 语句。情境解析模式确定将foreach解释为别名(因此引用foreach)  或作为陈述。

答案 1 :(得分:2)

PS C:\> Get-Help -Name 'ForEach-Object'

SYNTAX
    ForEach-Object [-MemberName] <String> [-ArgumentList <Object[]>] [-Confirm] [-InputObject <PSObject>] [-WhatIf] [<CommonParameters>]

    ForEach-Object [-Process] <ScriptBlock[]> [-Begin <ScriptBlock>] [-Confirm] [-End <ScriptBlock>] [-InputObject <PSObject>] [-RemainingScripts <ScriptBlock[]>] [-WhatIf] [<CommonParameters>]

通过使用脚本块,您可以使用ForEach-Object cmdlet的位置绑定参数。在这种情况下,-Process { }参数集。如果你逃离了行的末尾(本质上是逃避换行),你可以解决这个问题,但这通常是一种不好的做法。