【问题标题】:How can I repeat an iteration in a PowerShell foreach loop?如何在 PowerShell foreach 循环中重复迭代?
【发布时间】:2016-07-28 05:17:12
【问题描述】:

我经常需要在 PowerShell 中循环遍历数据集(SQL 结果、计算机列表等),每次都执行相同的操作(例如函数 X)。我几乎只使用foreach 循环,因为它们简单、有效且易于被可能需要遵循我的代码的其他人理解。

在重试失败的操作(最多 Y 次)的意义上,我想让我的一些代码更健壮。实现这一点的方法不止一种,例如 foreach 循环中,将函数 X 包装在 do{} while() 循环中。在这个例子中,假设函数 X 只有在“成功”时才返回非空结果:

foreach($dataitem in $dataset){
  $Result = $null
  $Attempts = 0
  do{
    $Attempts++
    $Result = <call function X on $dataitem>
  } while(($Attempts -lt 3) -and (-not $Result))
}

我想知道是否有任何方法可以将这个逻辑扁平化一点,即使用 foreach 循环的更高级方法,所以我可以取消 do{} while() 循环。

我遇到了与我想要的相反的情况,即使用$foreach.MoveNext() 在循环中向前跳过,但没有发现任何(危险的?)会使 foreach 处理相同项目的东西。

本质上:可以使用 foreach 循环重新进行迭代吗?

【问题讨论】:

    标签: loops powershell foreach


    【解决方案1】:

    我不会尝试重新执行 foreach 循环的迭代。这对我来说感觉不对。相反,我会创建一个实现类似retry-logic 模式的函数:

    function Retry-Process()
    {
        Param(
            [scriptblock]$action,
            [scriptBlock]$validator,
            [int]$retryCount
        )
    
        1 .. $retryCount | % {  
            $result = & $action
            if (& $validator ($result))
            {
                $result
                break
            }    
        }
    }
    

    调用示例:

    Retry-Process -action { '3' } -validator { Param($a)  $a -eq '3'} -retryCount 5
    

    在你的 foreach 循环中:

    foreach($dataitem in $dataset) {
      $Result = Retry-Process `
        -action { <call function X on $dataitem> } `
        -validator { Param($returnValue)  $returnValue } ` # Validate return value != null
        -retryCount 3
    }
    

    【讨论】:

    • 我喜欢这个提议,因此赞成,但最终我想知道是否有办法控制 foreach 遍历数组的方式。
    • 嗯,你可以用 for 循环来做这样的事情,例如for ($i = 1; $i -lt $dataset.count; $i++),如果它不是预期的结果,你只需递减$i。 Anway - 您需要的是众所周知的retry-logic 模式的实现。当您可以定义可重用函数时,我不会尝试使用 foreach 操作来实现。
    【解决方案2】:

    虽然我同意 Jisaak 的观点,但要回答您的问题,您可以使用以下方法来实现此目的

    foreach ($i in 1..10) {
        $i
        if ($limit++ -gt 10) { break } # just to stop infinite loop
    
        if ($i -eq 4) {
            foreach.Reset()
            1..($i-1) | Foreach-Object {
                   [void]$foreach.MoveNext()
            }
        }
    }
    

    当然,我不会在锻炼之外做任何这么愚蠢的事情。混合使用foreach() {}Foreach-Object 是为了简化自动IEnumeration 对象$foreach 的范围。

    编辑

    我认为包含指向将foreach 描述为关键字cmdlet 之间区别的页面的链接很有用:

    【讨论】:

    • 有趣;所以可以.Reset foreach 循环吗?然后在迭代结束之前让 foreach“光标”赶上前一个项目,嘿-presto,你现在正在重新处理你刚刚处理的同一个项目。
    • 而且我想我需要更加努力地思考foreachForeach-Object 之间的区别...
    • 好的,所以我不喜欢这个答案,因为我打算使用它,但它确实解决了我想知道的问题,即如何控制流程的foreach。
    猜你喜欢
    • 1970-01-01
    • 2021-07-21
    • 2013-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-11
    • 2020-02-20
    • 2013-03-23
    相关资源
    最近更新 更多