programing

PowerShell에서 ForEach-Object를 종료하는 방법

showcode 2023. 4. 10. 22:24
반응형

PowerShell에서 ForEach-Object를 종료하는 방법

다음 코드가 있습니다.

$project.PropertyGroup | Foreach-Object {
    if($_.GetAttribute('Condition').Trim() -eq $propertyGroupConditionName.Trim()) {
        $a = $project.RemoveChild($_);
        Write-Host $_.GetAttribute('Condition')"has been removed.";
    }
};

질문 1: ForEach-Object를 종료하려면 어떻게 해야 합니까?"break"과 "continue"를 사용하려고 했지만 작동하지 않습니다.

질문 #2: 저는 이 리스트의 변경 가능한 것을 발견했습니다.foreach루프...C#에서는 그렇게 할 수 없어요.PowerShell에서는 왜 이런 일을 할 수 있을까요?

일단은...Foreach-Object실제 루프가 아닌 콜링break스크립트 뒤에 있는 문장으로 건너뛰지 않고 스크립트 전체를 취소합니다.

반대로break그리고.continue실제에서는 기대대로 동작합니다.foreach고리.

항목 #1.puting a의 경우break의 범위 내에서foreachloop은 루프를 종료하지만 파이프라인을 정지하지는 않습니다.다음과 같은 것을 원하는 것처럼 들립니다.

$todo=$project.PropertyGroup 
foreach ($thing in $todo){
    if ($thing -eq 'some_condition'){
        break
    }
}

항목 #2.PowerShell을 사용하여 내부 어레이를 수정할 수 있습니다.foreach이러한 변경은 루프를 종료할 때까지 유효하게 되지 않습니다.예를 들어 아래 코드를 실행해 보십시오.

$a=1,2,3
foreach ($value in $a){
  Write-Host $value
}
Write-Host $a

PowerShell의 작성자가 왜 이것을 허용했는지에 대해서는 언급할 수 없지만, 대부분의 다른 스크립트 언어(Perl, Python 및 Shell)는 유사한 구성을 허용합니다.

사이에는 차이가 있다foreach그리고.foreach-object.

MS-ScriptingGuy에 대한 자세한 설명은 이쪽에서 확인하실 수 있습니다.

PS에서의 테스트에서는, 차이를 나타내는 스크립트를 소개합니다.

각 오브젝트:

# Omit 5.
1..10 | ForEach-Object {
if ($_ -eq 5) {return}
# if ($_ -ge 5) {return} # Omit from 5.
Write-Host $_
}
write-host "after1"
# Cancels whole script at 15, "after2" not printed.
11..20 | ForEach-Object {
if ($_ -eq 15) {continue}
Write-Host $_
}
write-host "after2"
# Cancels whole script at 25, "after3" not printed.
21..30 | ForEach-Object {
if ($_ -eq 25) {break}
Write-Host $_
}
write-host "after3"

앞지르다

# Ends foreach at 5.
foreach ($number1 in (1..10)) {
if ($number1 -eq 5) {break}
Write-Host "$number1"
}
write-host "after1"
# Omit 15. 
foreach ($number2 in (11..20)) {
if ($number2 -eq 15) {continue}
Write-Host "$number2"
}
write-host "after2"
# Cancels whole script at 25, "after3" not printed.
foreach ($number3 in (21..30)) {
if ($number3 -eq 25) {return}
Write-Host "$number3"
}
write-host "after3"

파이프라인을 정지하려면ForEach-Object부분적으로는 스테이트먼트를 사용합니다.continue스크립트 블록 안에ForEach-Object.continue에서 사용하는 경우는, 동작이 다릅니다.foreach(...) {...}및 인ForEach-Object {...}이것이 가능한 이유입니다.파이프라인에서 오브젝트를 생성하여 원래 오브젝트의 일부를 폐기하는 경우 가장 좋은 방법은 다음 방법을 사용하여 필터링하는 것입니다.Where-Object.

부터ForEach-Objectcmdlet입니다.break그리고.continue여기서는 다른 방법으로 행동할 것이다.foreach 키워드를 지정합니다.둘 다 루프를 정지하지만 스크립트 전체를 종료합니다.

브레이크:

0..3 | foreach {
    if ($_ -eq 2) { break }
    $_
}
echo "Never printed"

# OUTPUT:
# 0
# 1

속행:

0..3 | foreach {
    if ($_ -eq 2) { continue }
    $_
}
echo "Never printed"

# OUTPUT:
# 0
# 1

powershell core는 다음 방법을 사용하지만 스크립트를 깨지 않고 foreach 스크립트블록을 깨는 "좋은" 방법을 찾지 못했습니다.단, "남용" 예외는 제외합니다.

던지기:

class CustomStopUpstreamException : Exception {}
try {
    0..3 | foreach {
        if ($_ -eq 2) { throw [CustomStopUpstreamException]::new() }
        $_
    }
} catch [CustomStopUpstreamException] { }
echo "End"

# OUTPUT:
# 0
# 1
# End

(항상 가능한 것은 아니지만) 다른 방법은foreach 키워드:

포어치:

foreach ($_ in (0..3)) {
    if ($_ -eq 2) { break }
    $_
}
echo "End"

# OUTPUT:
# 0
# 1
# End

ForEach-Object를 계속 사용한다면 다음과 같은 "break condition"을 추가하는 것이 좋습니다.

$Break = $False;

1,2,3,4 | Where-Object { $Break -Eq $False } | ForEach-Object {

    $Break = $_ -Eq 3;

    Write-Host "Current number is $_";
}

위의 코드는 1, 2, 3을 출력한 후 건너뛰어야 합니다(Break before) 4.예상 출력:

Current number is 1
Current number is 2
Current number is 3

다음은 질문 #1에 대한 권장 접근법입니다.이 접근법은 ForEach-Object cmdlet을 사용하는 경우 사용합니다.EX가 아니기 때문에 질문에 직접 답변하지 않습니다.IT 파이프라인단, Q#1에서 원하는 효과를 얻을 수 있습니다.저와 같은 아마추어들이 볼 수 있는 유일한 단점은 대규모 파이프라인 반복을 처리하는 것입니다.

    $zStop = $false
    (97..122) | Where-Object {$zStop -eq $false} | ForEach-Object {
    $zNumeric = $_
    $zAlpha = [char]$zNumeric
    Write-Host -ForegroundColor Yellow ("{0,4} = {1}" -f ($zNumeric, $zAlpha))
    if ($zAlpha -eq "m") {$zStop = $true}
    }
    Write-Host -ForegroundColor Green "My PSVersion = 5.1.18362.145"

이게 도움이 됐으면 좋겠어요.모두 새해 복 많이 받으세요.

할 수 있는 .ForEach-Object예외 없이.이것은, 보다 덜 알려진 기능을 채용하고 있습니다.Select-Object-First 지정된 수의 파이프라인 항목이 처리되면 실제로 파이프라인이 중단됩니다.

간단한 예:

$null = 1..5 | ForEach-Object {

    # Do something...
    Write-Host $_
 
    # Evaluate "break" condition -> output $true
    if( $_ -eq 2 ) { $true }  
 
} | Select-Object -First 1     # Actually breaks the pipeline

출력:

1
2

해 주세요.$null 은 은근히 은근히 은근히 .$true이 값은 브레이크 조건에 의해 생성됩니다.$true할 수 42,"skip","foobar"만 해뭐든지 말씀해 보세요.로 뭘 좀 하면 돼Select-Object이치노

특정 코드 블록에서 세분화된 흐름 제어를 해제하는 방법을 찾다가 이 질문을 발견했습니다.내가 결정한 해결책은 언급되지 않았다...

break 키워드를 지정한 라벨 사용

송신원: about_break

Break 문에는 내장된 루프를 종료할 수 있는 라벨을 포함할 수 있습니다.라벨은 스크립트에서 Forech, For, While 등의 임의의 루프 키워드를 지정할 수 있습니다.

여기 간단한 예가 있습니다.

:myLabel for($i = 1; $i -le 2; $i++) {
        Write-Host "Iteration: $i"
        break myLabel
}

Write-Host "After for loop"

# Results:
# Iteration: 1
# After for loop

더 복잡한 예에서는 중첩된 레이블과 각 레이블이 구분된 결과를 보여 줍니다.

:outerLabel for($outer = 1; $outer -le 2; $outer++) {

    :innerLabel for($inner = 1; $inner -le 2; $inner++) {
        Write-Host "Outer: $outer / Inner: $inner"
        #break innerLabel
        #break outerLabel
    }

    Write-Host "After Inner Loop"
}

Write-Host "After Outer Loop"

# Both breaks commented out
# Outer: 1 / Inner: 1
# Outer: 1 / Inner: 2
# After Inner Loop
# Outer: 2 / Inner: 1
# Outer: 2 / Inner: 2
# After Inner Loop
# After Outer Loop

# break innerLabel Results
# Outer: 1 / Inner: 1
# After Inner Loop
# Outer: 2 / Inner: 1
# After Inner Loop
# After Outer Loop

# break outerLabel Results
# Outer: 1 / Inner: 1
# After Outer Loop

코드 블록을 루프로 감싸서 다른 상황에서 동작하도록 조정할 수도 있습니다.이러한 번만 실행됩니다.

:myLabel do {
    1..2 | % {

        Write-Host "Iteration: $_"
        break myLabel

    }
} while ($false)

Write-Host "After do while loop"

# Results:
# Iteration: 1
# After do while loop

에는 두 가 있습니다.ForEach-ObjectPowerShell:

  1. 출구 합니다.Where-Object물건을 .Foreach-Object 「」
  2. 한 경우) convert (변환)Foreach-ObjectForeach루핑 구조

예를 들어 보겠습니다.다음 스크립트는 두 번째 반복 후 Foreach-Object 루프에서 종료됩니다(즉, 파이프라인이 2회만 반복).

솔루션 1: 사용Where-Object BeforeForeach-Object:

[boolean]$exit = $false;
1..10 | Where-Object {$exit -eq $false} | Foreach-Object {
     if($_ -eq 2) {$exit = $true}    #OR $exit = ($_ -eq 2);
     $_;
}

또는

1..10 | Where-Object {$_ -le 2} | Foreach-Object {
     $_;
}

솔루션 2: 변환 완료Foreach-ObjectForeach프프: :

Foreach ($i in 1..10) { 
     if ($i -eq 3) {break;}
     $i;
}

PowerShell은 실제로 본체 에서 보다 쉽게 종료 또는 분리할 수 있는 방법을 제공해야 합니다.Foreach-Object파이프라인.주의:return않고 .continue는.return:

Write-Host "Following will only skip one iteration (actually iterates all 10 times)";
1..10 | Foreach-Object {
     if ($_ -eq 3) {return;}  #skips only 3rd iteration.
     $_;
}

HTH

질문 1에 대한 답변 - if 스테이트먼트가 TRUE가 되지 않도록 하기만 하면 됩니다.

$project.PropertyGroup | Foreach {
    if(($_.GetAttribute('Condition').Trim() -eq $propertyGroupConditionName.Trim()) -and !$FinishLoop) {
        $a = $project.RemoveChild($_);
        Write-Host $_.GetAttribute('Condition')"has been removed.";
        $FinishLoop = $true
    }
};

언급URL : https://stackoverflow.com/questions/10277994/how-to-exit-from-foreach-object-in-powershell

반응형