about_Foreach 示例:PowerShell 中的 cmd 子例程语法?

about_Foreach example: cmd subroutine syntax in PowerShell?

this about page中,有一个代码块(下图)展示了$ForEach自动变量,但它也有类似批处理子程序的语法。我找不到关于这段代码如何运行或调用什么语言结构的文档。我相信这是 PowerShell v5 的补充,但阅读发行说明对我也没有帮助。 :tokenLoop foreach ($token in $tokens)代表什么?

function Get-FunctionPosition {
  [CmdletBinding()]
  [OutputType('FunctionPosition')]
  param(
    [Parameter(Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [ValidateNotNullOrEmpty()]
    [Alias('PSPath')]
    [System.String[]]
    $Path
  )

  process {
    try {
      $filesToProcess = if ($_ -is [System.IO.FileSystemInfo]) {
        $_
      }
      else {
        Get-Item -Path $Path
      }
      foreach ($item in $filesToProcess) {
        if ($item.PSIsContainer -or $item.Extension -notin @('.ps1', '.psm1')) {
          continue
        }
        $tokens = $errors = $null
        $ast = [System.Management.Automation.Language.Parser]::ParseFile($item.FullName, ([REF]$tokens), ([REF]$errors))
        if ($errors) {
          Write-Warning "File '$($item.FullName)' has $($errors.Count) parser errors."
        }
        :tokenLoop foreach ($token in $tokens) {
          if ($token.Kind -ne 'Function') {
              continue
          }
          $position = $token.Extent.StartLineNumber
          do {
            if (-not $foreach.MoveNext()) {
              break tokenLoop
            }
            $token = $foreach.Current
          } until ($token.Kind -in @('Generic', 'Identifier'))
          $functionPosition = [pscustomobject]@{
            Name       = $token.Text
            LineNumber = $position
            Path       = $item.FullName
          }
          Add-Member -InputObject $functionPosition -TypeName FunctionPosition -PassThru
        }
      }
    }
    catch {
      throw
    }
  }
}

在 PowerShell 3.0 版及更高版本(至少从 2.0 版开始),以下语句类型可选择标记为

  • switch
  • foreach
  • for
  • while
  • do

现在,这是什么意思?这意味着您可以在标记语句的主体内提供标签名称作为 breakcontinue 语句的参数,并将流控制应用于标签指示的语句。

考虑这个例子:

foreach($Name in 'Alice','Bob','Charlie'){
    switch($Name.Length){
        {$_ -lt 4} {
            # We don't have time for short names, go to the next person
            continue
        }
        default {
            Write-Host "$Name! What a beautiful name!"
        }
    }

    Write-Host "Let's process $Name's data!"
}

您可能希望 "Let's process [...]" 字符串只出现两次,因为我们 continueBob 的情况下,但由于直接父语句是 switch ,它实际上并不适用于 foreach 语句。

现在,如果我们可以明确声明我们要继续 foreach 循环而不是 switch 语句,我们就可以避免:

:outer_loop
foreach($Name in 'Alice','Bob','Charlie'){
    switch($Name.Length){
        {$_ -lt 4} {
            # We don't have time for short names, go to the next person
            continue outer_loop
        }
        default {
            Write-Host "$Name! What a beautiful name!"
        }
    }

    Write-Host "Let's process $Name's data!"
}

现在 continue 语句实际上继续循环而不是切换。

当你有嵌套的循环结构时非常有用。


标签在 about_Break help topic

中的 while 语句中与 break 一起简要讨论