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

问题描述 投票:0回答:2

好的,这个脚本的预期“输出”是相当明显的,并且它有效。它复制文件:

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 是否要求其大括号位于同一行?

powershell syntax
2个回答
9
投票

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

  • 参数模式是面向行的并且是类似shell:它适用于调用可执行文件/脚本/cmdlet/别名/函数的单个命令,或与管道符号链接的一系列此类命令(

    |
    )形成管道。

    • 每个单独的命令必须在自己的行上,将其分散到多行的唯一方法是使用行延续,这需要使用

      `
      (反引号)转义每个内部行的最末尾).
      然而,这种做法在视觉上既微妙又脆弱(在
      `
      中断命令之后甚至只放置空格或制表符)。

    • 为了将 pipeline 的各个命令分散到多行(无需使用续行),请以

      |
      结束除最后一行之外的每一行。

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

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

有关解析模式的官方文档位于概念性

about_Parsing
帮助主题


ForEach-Object
是一个 cmdlet,因此以 参数模式 进行解析。

因此,除非您使用行继续,否则它不会在后续行上查找参数,并且在不带参数的情况下自行执行

ForEach-Object
,会导致它提示输入其强制参数 -
 -Process
脚本块 - 这就是您所看到的。

相比之下,尽管脚本块在后续行中继续,但

... | ForEach-Object {
仍然有效,因为脚本块本身是在表达式模式下解析的,允许它分布在多行中,而starting脚本块 - 开头
{
- 与
ForEach-Object
在同一行足以让
ForEach-Object
识别它。


对比以 argument 模式解析的

cmdlet
ForEach-Object 与以
表达式模式解析的 
foreach statement 的示例[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
有一个 alias,也称为
foreach
,它模糊了 cmdlet 和
foreach
statement 之间的区别。情境解析模式决定
foreach
是否被解释为别名(因此指的是
ForEach-Object
) 或作为声明。


3
投票
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 { }
参数。如果您转义行尾(本质上是转义换行符),您可以解决这个问题,但这通常是一个不好的做法。

© www.soinside.com 2019 - 2024. All rights reserved.