Foreach-Object에서 '계속'이 '중단'처럼 동작하는 이유는 무엇입니까?


123

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를 수행하는 동안 유사한 동작을 얻을 수 있으므로 파이프 라인을 분리 할 필요가 없습니까?


여기에 사용하는 명령의 많은 페이지입니다 foreach: techotopia.com/index.php/...
bgmCoder

여기에서 괜찮은 설명과 샘플을 찾았습니다 ... powershell.com/cs/blogs/tips/archive/2015/04/27/…
Nathan Hartley

답변:


164

단순히 사용하는 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.


2
영업 이익은 분명히 무슨 말에서 continue을 시뮬레이션 할 수 있습니다 breakForEach-Object:)
리처드 하우어

6
@ Richard Hauer 그런 것은 그것이 사용되는 곳 continue뿐만 아니라 전체 스크립트를 깨뜨릴 ForEach-Object것입니다.
로마 쿠즈 민

22

때문에 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}

Where-Object cmdlet을 사용하는 것이 좋습니다. 제 실제 경우에는 if 문 앞에있는 여러 줄의 코드를 읽기 어려운 단일 긴 줄로 만드는 것이 합리적이지 않다고 생각합니다. 그러나 그것은 다른 상황에서 저에게 효과적입니다.
Justin Dearing

@JustinDearing- In my actual case, I don't think it makes sense to make the multiple lines of code preceding my if statement into a single long line of hard to read code.무슨 말이야?
manojlds

3
@manojlds 아마도 그는 당신의 한 줄 솔루션이 "읽기 어렵다"고 생각할 것입니다. 적어도 저에게는 그 반대입니다. 작업을 수행하는 파이프 라인 방식은 정말 강력하고 명확하며 이와 같은 간단한 작업에 대한 올바른 접근 방식입니다. 그것을 이용하지 않고 쉘에 코드를 작성하는 것은 의미가 없습니다.
mjsr

제 경우에는 이것이 정답이었습니다. 처음부터 처리 할 필요가 없도록 계속하거나 복귀 할 객체를 필터링하는 where 조건을 추가합니다. +1
Chris Magnuson 2015

3

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

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

4
솔직히, 그것은 추악합니다 :) 그리고 foreach-object 대신 foreach 루프를 사용할 수 있기 때문에 해킹이 아닙니다.
manojlds

1
@manojlds : 1..100은 설명 용입니다. do {} while ($ False)는 for 루프와 마찬가지로 작동하며 좀 더 직관적입니다.
Harry Martyrossian

2

간단한 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"}}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.