[powershell] Foreach-Object에서 ‘계속’이 ‘중단’처럼 동작하는 이유는 무엇입니까?

PowerShell 스크립트에서 다음을 수행하는 경우 :

$range = 1..100
ForEach ($_ in $range) {
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}

예상되는 결과는 다음과 같습니다.

7 is a multiple of 7
14 is a multiple of 7
21 is a multiple of 7
28 is a multiple of 7
35 is a multiple of 7
42 is a multiple of 7
49 is a multiple of 7
56 is a multiple of 7
63 is a multiple of 7
70 is a multiple of 7
77 is a multiple of 7
84 is a multiple of 7
91 is a multiple of 7
98 is a multiple of 7

나는 파이프 라인을 사용하는 경우에는 ForEach-Object, continue파이프 라인 루프의 탈옥 것으로 보인다.

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}

continueForEach-Object를 수행하는 동안 유사한 동작을 얻을 수 있으므로 파이프 라인을 분리 할 필요가 없습니까?



답변

단순히 사용하는 return대신의 continue. 이것은 특정 반복에서 return호출되는 스크립트 블록에서 반환 ForEach-Object되므로 continuein a 루프를 시뮬레이션합니다 .

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { return }
    Write-Host "$($_) is a multiple of 7"
}

리팩토링 할 때 염두에 두어야 할 사항이 있습니다. 때때로 cmdlet foreach을 사용 하여 명령문 블록을 파이프 라인으로 변환하려고합니다 ForEach-Object( foreach이 변환을 쉽게 수행하고 실수도 쉽게 만드는 데 도움 이되는 별칭 도 있음). 모두 continue들로 대체해야return .

추신 : 불행하게도, 시뮬레이션이 쉽지 않다 break에서 ForEach-Object.


답변

때문에 For-Each개체는 cmdlet을하지 루프이고 continue그리고 break그것을 적용되지 않습니다.

예를 들어 다음과 같은 경우 :

$b = 1,2,3

foreach($a in $b) {

    $a | foreach { if ($_ -eq 2) {continue;} else {Write-Host $_} }

    Write-Host  "after"
}

다음과 같이 출력됩니다.

1
after
3
after

continue가져 오기가 foreach-object cmdlet이 아니라 외부 foreach 루프에 적용 되기 때문 입니다. 루프가 없으면 가장 바깥 쪽 레벨이므로 break.

그렇다면 어떻게 continue같은 행동을하게 될까요? 한 가지 방법은 물론 Where-Object 입니다.

1..100 | ?{ $_ % 7  -eq 0} | %{Write-Host $_ is a multiple of 7}


답변

또 다른 대안은 일종의 해킹이지만 한 번 실행되는 루프로 블록을 래핑 할 수 있습니다. 그렇게 continue하면 원하는 효과를 얻을 수 있습니다.

1..100 | ForEach-Object {
    for ($cont=$true; $cont; $cont=$false) {
        if ($_ % 7 -ne 0 ) { continue; }
        Write-Host "$($_) is a multiple of 7"
    }
}


답변

간단한 else문장으로 다음과 같이 작동합니다.

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) {
        # Do nothing
    } else {
        Write-Host "$($_) is a multiple of 7"
    }
}

또는 단일 파이프 라인에서 :

1..100 | ForEach-Object { if ($_ % 7 -ne 0 ) {} else {Write-Host "$($_) is a multiple of 7"}}

그러나 더 우아한 해결책은 테스트를 뒤집고 성공에 대해서만 출력을 생성하는 것입니다.

1..100 | ForEach-Object {if ($_ % 7 -eq 0 ) {Write-Host "$($_) is a multiple of 7"}}


답변