자바스크립트를 활성화 해주세요

p043 Powershell의 Begin Process End 사용하기

 ·  ☕ 3 min read

Advanced Methods ?

CmdletBinding 을 사용하면, 좀 더 부가적인 기능을 사용할 수 있다라고 합니다. 그중에 하나가 Begin, Process, End 블럭을 사용할 수 있다라고 소개하고 있는데, 실제로는 CmdletBinding 없이도 Begin, Process, End는 사용할 수 있습니다.

실행은 Begin, Process, End 의 순서대로 실행됩니다. 느낌은 마치 Perl의 Begin과 End 블럭과 같은 느낌 합니다. 기본적인 사용법은 다음과 같습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
PS C:\Users\Administrator> function test-function {
    Begin { Write-Host 1 }
    Process { Write-Host 2}
    End { Write-Host 3}
}

test-function
1
2
3

그런데, 반복되는 타이밍에 대해서는 블럭간에 조금 다른 움직임이 있습니다.

실행되는 타이밍

다음과 같이 파이프라인으로 변수를 입력받는 경우가 있다고 하면, 이에 대한 실행은 어떻게 될까요?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Function Test-ScriptCmdlet {
    [CmdletBinding()]
    Param (
        [Parameter(ValueFromPipeline=$true)]
        [string] $WorkItem
    )
    Begin{1}
    Process{
        $WorkItem
    }
    End{3}
}

"one", "two", "three" | Test-ScriptCmdlet

실제로 실행시킨 결과는 다음과 같습니다. Process에 해당되는 부분만 파이프로 주어진 수 만큼 실행되었습니다. Begin과 End는 각각 한번만 실행되었습니다.

1
2
3
4
5
6
"one", "two", "three" | Test-ScriptCmdlet
1
one
two
three
3

마치 UnitTest에서 테스트를 실행하기 전과 실행한 후에 딱 한 번씩 실행되는 코드부분과 같은 느낌입니다.

문제점

모든 Block에서 리턴을 하는 값이 있다면 어떻게 될까요?

예를들면 Begin에서 Validation을 실행하고 문제가 있을 경우에 에러를 리턴하게 한다면 어떻게 될까요? 언뜻 생각하기에는 Begin에서 return하고 있기 때문에 Process나 End까지는 실행되지 않을 것 같습니다.

1
2
3
4
5
6
7
function test-function {
    Begin { return 1 }
    Process { return 2}
    End { return 3}
}

test-function

하지만 예상과는 다르게 결과는 모든 Block이 실행되어 버리기 때문에 모두 return 하게 됩니다. 마치 python의 yield와 같은 효과가 나타납니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
PS C:\Windows\system32> $a = test-function
PS C:\Windows\system32> $a
1
2
3
PS C:\Windows\system32> $a.GetType()

IsPublic IsSerial Name     BaseType
-------- -------- ----     --------
True     True     Object[] System.Array      

그렇기 때문에 Begin과 End를 Validation처럼 사용하는 것은 조금 생각을 개선해야 할 필요가 있습니다.

개선

만일 억지로 Begin을 Validation으로 사용하고 싶다라고 한다면, Begin, Process, End 구문을 도입한 함수는 형식이 다음과 같이 처리되어야 합니다. 약간 verbose하고 사용방법을 강제해 버리기 때문에, 위화감이 살짝 드는 경우도 있을 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function test-function2 {
    Begin { $retval = "begin" }
    Process { 
        
        $retval = "process" 
        return

        $retval = "process2" # not rechable
    }
    End { return $retval }
}

$b = test-function2
$b
$b.GetType()

결과는 다음과 같습니다.

1
2
3
4
5
6
7
PS C:\Windows\system32> $b = test-function2

PS C:\Windows\system32> $b.GetType()

IsPublic IsSerial Name     BaseType
-------- -------- ----     --------
True     True     String   System.Object

기타

  • Begin에서 throw가 걸리면, Process, End까지 가지 않고 바로 Exception이 발동됩니다.
  • 만약에 C#으로 Cmdlet을 만드는 경우 ShouldProcess 함수는 Process에서만 사용할 수 있다고 합니다. 단, [CmdletBinding(SupportsShouldProcess=$True)] 과 함께 쓰여졌을 때에만 한한다고 합니다.

결론

Begin Process End 는 언제 쓰면 될까를 생각해보면, 여러개의 파라메터가 주어졌을 때, 딱 한번만 처리해야 할 필요가 있을 때 사용하면 될 것 같습니다. 이러한 경우를 생각해서 함수를 생각한다면 좀 고차원적인 함수 설계가 될 것 같습니다.

레퍼런스

공유하기

tkim
글쓴이
tkim
Software Engineer