Windows PowerShell정규식 작성

Don Jones

192.168.4.5. \\Server57\Share. johnd@contoso.com. 이 세 항목이 IP 주소, UNC(범용 명명 규칙) 경로, 그리고 전자 메일 주소라는 사실을 모르는 독자는 없겠죠. 뇌에서 각각의 형식을 인지하는 것입니다. 네 부분으로 이루어진 숫자, 백슬래시, @ 기호 및 기타 형식이 이 문자열이 어떤 데이터를

나타내는지 말해 줍니다. 그리고 조금만 생각해보면 192.168만으로는 유효한 IP 주소가 아니고, 7\\Server2\\Share가 유효한 UNC가 아니고, joe@contoso가 유효한 전자 메일 주소가 아니라는 사실도 쉽게 알 수 있습니다.

안타깝게도 컴퓨터의 경우 이렇게 복잡한 형식을 "이해"하려면 다소 노력이 필요합니다. 이때 바로 정규식이 필요한 것입니다. 정규식은 특수한 정규식 언어를 사용하여 작성된 문자열로, 컴퓨터에서 IP 주소, UNC 또는 전자 메일 주소와 같은 특정 형식의 문자열을 식별하는 데 사용됩니다. 잘 작성된 정규식은 Windows PowerShellTM 스크립트에서 유효한 데이터를 수락하거나 지정한 형식에 맞지 않는 잘못된 데이터를 거부하도록 할 수 있습니다.

간단한 match 만들기

Windows PowerShell –match 연산자는 문자열을 정규식(또는 regex)과 비교한 다음 문자열이 정규식과 일치하는지 여부에 따라 True 또는 False를 반환합니다. 아주 간단한 정규식의 경우 특수한 구문을 사용할 필요 없이 리터럴 문자만으로도 충분합니다. 예를 들면 다음과 같습니다.

"Microsoft" –match "soft"
"Software" –match "soft"
"Computers" –match "soft"

첫 번째 식을 Windows PowerShell에서 실행하면 True가 반환되고 세 번째 식을 실행하면 False가 반환됩니다. 각각의 식은 문자열, –match 연산자, 정규식으로 이루어져 있습니다. 기본적으로 정규식은 문자열을 따라 흐르듯이 일치하는 결과를 찾습니다. "soft"라는 문자열은 Software와 Microsoft에 모두 포함되어 있지만 위치가 다릅니다. 또한 기본적으로 정규식에서는 대/소문자가 구분되지 않습니다. 따라서 대문자 S로 시작하는 "Software"에서도 "soft"가 검색됩니다.

필요에 따라 다음과 같이 –cmatch 연산자를 사용하여 대/소문자를 구분하는 정규식을 작성할 수 있습니다.

"Software" –cmatch "soft"

이 식의 경우 대/소문자를 구분하므로 "soft"가 "Software"에서 검색되지 않아 False가 반환됩니다. 대/소문자를 구분하지 않는 명시적인 옵션으로 –imatch 연산자를 사용할 수도 있습니다(–match의 기본 동작과 동일).

와일드카드 및 반복기

정규식에는 와일드카드 문자를 몇 개 사용할 수 있습니다. 예를 들어 마침표는 한 문자를 나타내고 물음표는 문자가 없거나 하나 있는 경우를 나타냅니다. 다음은 몇 가지 예제입니다.

"Don" –match "D.n" (True)
"Dn" –match "D.n" (False)
"Don" –match "D?n" (True)
"Dn" –match "D?n" (True)

첫 번째 식에서 마침표는 한 문자만 나타내므로 검색 결과가 True가 됩니다. 두 번째 식의 경우 마침표에 해당하는 한 문자가 없으므로 검색 결과가 False가 됩니다. 세 번째와 네 번째 식에서 보듯이 물음표는 알 수 없는 문자 하나 또는 문자가 없는 경우에 해당합니다. 마지막으로, 네 번째 식에서는 "D"와 "n"이 모두 있고 그 사이에 문자가 없으므로 결과가 True가 됩니다. 즉, 물음표는 선택적인 문자를 나타내는 데 사용할 수 있으므로 해당 위치에 문자가 없더라도 결과가 True가 됩니다.

또한 정규식에서는 * 및 + 기호가 반복기로 인식됩니다. 이러한 반복기는 하나 이상의 특정 문자 뒤에 사용해야 합니다. *는 0개 이상의 지정된 문자를 나타내고, +는 하나 이상의 지정된 문자를 나타냅니다. 다음은 몇 가지 예제입니다.

"DoDon" –match "Do*n" (True)
"Dn" -match "Do*n" (True)
"DoDon" -match "Do+n" (True)
"Dn" -match "Do+n" (False)

*와 +는 모두 "o"만이 아니라 "Do"를 검색합니다. 이러한 반복기는 특정 문자가 아니라 일련의 문자를 검색하기 때문입니다.

마침표, *, ? 또는 + 기호 자체를 검색할 경우에는 어떻게 해야 할까요? 이 경우 해당 기호 앞에 정규식 이스케이프 문자인 백슬래시를 추가하면 됩니다.

"D.n" -match "D\.n" (True)

이는 Windows PowerShell 이스케이프 문자(역아포스트로피)와는 다르지만 업계 표준 정규식 구문을 따릅니다.

문자 클래스

문자 클래스는 전체 문자 그룹을 나타내는 확장된 형태의 와일드카드입니다. Windows PowerShell에서는 다음과 같은 몇 가지 문자 클래스가 인식됩니다.

  • \w는 문자 및 숫자를 포함한 모든 단어 문자를 나타냅니다.
  • \s는 탭, 공백 등의 모든 공백 문자를 나타냅니다.
  • \d는 모든 숫자를 나타냅니다.

부정 문자 클래스도 있습니다. 예를 들어 \W는 모든 비단어 문자를, \S는 비공백 문자를, \D 비숫자 문자를 나타냅니다. 이러한 클래스 뒤에는 복수의 검색 결과가 허용됨을 나타내는 * 또는 +를 사용할 수 있습니다. 다음은 몇 가지 예제입니다.

"Shell" -match "\w" (True)
"Shell" -match "\w*" (True)

이달의 Cmdlet

Write-Debug cmdlet는 Debug 파이프라인에 텍스트 문자열과 같은 개체를 작성하는 데 매우 유용합니다. 그러나 셸에서 이 cmdlet를 사용하면 별다른 효과가 없는 것처럼 보이기 때문에 다소 실망스러울 수 있습니다.

그 이유는 Debug 파이프라인이 기본적으로 차단되기 때문입니다. 즉, $DebugPreference 변수가 "SilentlyContinue"로 설정됩니다. 이 변수를 "Continue"로 설정하면 Write-Debug를 사용하여 전송하는 내용이 모두 콘솔에서 노란색 텍스트로 나타납니다. 복잡한 스크립트의 실행 상태를 추적할 수 있도록 스크립트에 추적 코드를 추가할 때에는 이보다 좋은 방법이 없습니다. 노란색은 추적된 내용과 스크립트의 일반 출력을 서로 구분하는 데 도움이 되며, 언제든지 Write-Debug 문을 모두 제거하지 않고도 디버그 메시지를 숨길 수 있습니다. 즉, $DebugPreference = "SilentlyContinue"로 다시 설정하면 디버그 텍스트가 사라집니다.

두 식은 모두 True를 반환하지만 검색되는 내용은 크게 다릅니다. 다행히 검색 결과가 발견될 때마다 $matches라는 변수에 검색 결과가 채워지므로 –match 연산자의 작동 상태를 확인할 수 있습니다. 다시 말해 정규식에 따라 연산자에 의해 검색된 문자열의 문자가 모두 이 변수로 보내집니다. $matches 변수는 –match 연산자를 사용하여 다른 정의 검색 결과가 발견될 때까지 결과를 유지합니다. 그림 1은 방금 살펴본 두 식의 차이점을 보여 줍니다. 여기서 보듯이 \w는 "Shell"에서 "S"에 해당하고 \w*는 전체 단어에 해당합니다.

그림 1 *의 기능

그림 1** *의 기능 **(더 크게 보려면 이미지를 클릭하십시오.)

문자 그룹, 범위 및 크기

정규식에는 문자의 그룹 또는 범위를 대괄호로 묶어 사용할 수 있습니다. 예를 들어 [aeiou]는 a, e, i, o 또는 u 중 해당하는 문자를 모두 검색합니다. [a-zA-Z]는 a-z 또는 A-Z 사이의 문자를 모두 검색합니다. 대/소문자를 구분하지 않는 –match 연산자를 사용하더라도 a-z 또는 A-Z 자체로도 대/소문자가 구분됩니다. 예를 들면 다음과 같습니다.

"Jeff" -match "J[aeiou]ff" (True)
"Jeeeeeeeeeeff" -match "J[aeiou]ff" (False)

중괄호를 사용하여 최소 문자 수 또는 최대 문자 수를 지정할 수도 있습니다. {3}은 지정한 세 문자만 정확히 검색하라는 의미이고, {3,}은 문자를 3개 이상 검색하라는 의미이며, {3,4}는 3개 이상 4개 이하로 검색하라는 의미입니다. 이는 IP 주소를 검색하는 정규식을 만드는 데 적합합니다.

"192.168.15.20" -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" (True)

이 정규식은 각각 1-3개의 숫자로 이루어지고 서로 리터럴 마침표로 구분된 4개의 숫자 그룹을 검색합니다. 그런데 다음 예제를 살펴보십시오.

"300.168.15.20" -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" (True)

이 예제는 정규식의 한계를 보여 줍니다. 즉, 이 문자열의 형식은 IP 주소처럼 보이지만 유효한 IP 주소가 아닙니다. 정규식은 데이터가 실제로 유효한지를 확인하지는 못하고 데이터의 형식이 올바른지만 확인합니다.

흐르지 않게 하기

정규식과 관련한 문제는 해결하기가 까다로울 수 있습니다. 예를 들어 \\Server2\Share라는 형식의 UNC 경로를 테스트하는 다음 정규식을 살펴보십시오.

"\\Server2\Share" -match "\\\\\w+\\\w+" (True)

여기서 테스트할 모든 리터럴 백슬래시는 다른 백슬래시로 이스케이프해야 하므로 정규식 자체를 읽기가 어렵습니다. 제대로 작동할 것 같지만 사실은 그렇지 않습니다.

"57\\Server2\Share" -match "\\\\\w+\\\w+" (True)

우리는 이 두 번째 예제가 유효한 UNC 경로가 아니라는 것을 쉽게 알 수 있지만 정규식에서는 유효한 것으로 나타납니다. 이유가 무엇일까요? 정규식은 기본적으로 흐르듯이 실행됩니다. 이 정규식은 2개의 백슬래시, 하나 이상의 문자와 숫자, 다른 백슬래시, 그리고 추가 문자와 숫자를 검색할 뿐입니다. 해당 문자열에는 이러한 패턴이 존재하지만 앞에 불필요한 숫자가 더 있으므로 유효한 UNC가 아닙니다. 이러한 문제를 해결하려면 문자열을 따라 흐르듯이 검색하지 않고 문자열의 시작 부분에서 검색을 시작하도록 해야 합니다. 이를 위해서는 다음과 같이 작성하면 됩니다.

"57\\Server2\Share" -match "^\\\\\w+\\\w+" (False)

^ 문자는 문자열이 시작되는 위치를 나타냅니다. 이 문자를 추가하면 정규식이 처음 두 문자가 백슬래시인 문자열을 찾으므로 이 경우와 같이 잘못된 UNC 경로는 검색되지 않습니다.

이와 유사하게 $ 기호를 사용하여 문자열의 끝을 나타낼 수 있습니다. UNC 경로에는 \\Server2\Share\Folder\File과 같이 경로 부분이 추가될 수 있으므로 이 문자가 그다지 유용하지 않습니다. 그러나 문자열의 끝을 지정해야 하는 경우는 수도 없이 많습니다.

정규식 관련 도움말

Windows PowerShell의 about_regular_expressions 도움말 항목에 정규식 언어에 대한 기본 구문 설명이 나와 있지만 온라인 리소스를 통해 보다 자세한 정보를 얻을 수 있습니다. 예를 들어 필자가 애용하는 www.RegExLib.com 웹 사이트에는 다양한 용도로 작성된 무료 정규식 라이브러리가 공개되어 있습니다. 이 사이트에서 "e-mail" 또는 "UNC"와 같은 키워드를 검색하면 필요에 맞는 정규식이나 필요한 정규식을 만드는 기반으로 사용할 정규식을 쉽게 찾을 수 있습니다. 뛰어난 정규식을 작성했다면 다른 사람들이 이용하도록 라이브러리에 게시할 수도 있습니다.

RegexBuddy(www.RegexBuddy.com)도 필자가 즐겨 사용하는 리소스입니다. 이 저렴한 도구는 그래픽 정규식 편집기를 제공합니다. RegexBuddy를 사용하면 복잡한 정규식을 쉽게 작성할 수 있을 뿐만 아니라, 정규식이 제대로 유효한 문자열을 허용하고 잘못된 문자열을 거부하는지 테스트할 수 있습니다. 다른 소프트웨어 개발자들도 무료 소프트웨어, 쉐어웨어 또는 상용으로 사용자에게 유용한 정규식 편집기와 테스터를 제공하고 있습니다.

정규식 사용

정규식이 실용성이 있는지 의문을 가질 수도 있습니다. CSV 파일에서 정보를 읽어 Active Directory®에 새 사용자를 만드는 데 사용한다고 생각해 보십시오. 다른 사람이 CSV 파일을 작성했다면 들어 있는 데이터의 형식이 올바른지 확인해야 할 수 있습니다. 이 작업에는 정규식이 이상적입니다. 예를 들어 \w+와 같은 간단한 정규식으로도 첫 번째 이름과 마지막 이름에 특수 문자 또는 기호가 없는지를 확인할 수 있으며, 조금 더 복잡한 정규식을 사용하면 전자 메일 주소가 회사 표준에 맞는지도 확인할 수 있습니다. 예를 들어 다음과 같은 정규식을 사용할 수 있습니다.

"^[a-z]+\.[a-z]+@contoso.com$"

이 정규식은 don.jones@contoso.com의 전자 메일 주소만 검색합니다. 여기서 첫 번째 이름과 마지막 이름에는 문자만 포함될 수 있고, 각 이름은 마침표로 구분되어야 합니다. 전자 메일 주소에 대한 정규식은 작성하기가 가장 까다롭습니다. 그러나 특정 회사 표준에 맞도록 범위를 한정하면 작성하기가 수월해집니다.

contoso.com 뒤에는 문자가 없고 사용자의 이름에 해당하는 문자 앞에는 다른 문자가 없음을 나타내는 시작 앵커와 끝 앵커(^ 및 $)를 잊어서는 안 됩니다.

사실 Windows PowerShell에서 정규식은 어렵지 않게 사용할 수 있습니다. $email 변수에 CSV 파일에서 읽은 전자 메일 주소가 들어 있다면 다음과 같은 정규식으로 해당 주소가 유효한지 여부를 확인할 수 있습니다.

$regex = "^[a-z]+\.[a-z]+@contoso.com$"
If ($email –notmatch $regex) {
  Write-Error "Invalid e-mail address $email" 
}

이 예제에는 -notmatch라는 새로운 연산자가 사용되었습니다. 이 연산자는 문자열이 제공한 정규식과 일치하지 않는 경우 True를 반환합니다. 또한 대/소문자를 구분하여 검색하는 –cnotmatch 연산자도 사용되었습니다.

추가 문자 클래스, 고급 연산자, 한두 가지 다른 연산자 등 정규식과 관련하여 이 기사에서 다루지 않은 내용도 많습니다. 또한 Windows PowerShell에서는 [regex]라는 개체 형식도 지원됩니다. 그러나 정규식을 처음 접하는 독자에게는 여기서 대략적으로 다룬 내용만으로도 충분하리라 믿습니다. 매우 어려운 정규식 관련 문제에 봉착한 경우 언제라도 www.ScriptingAnswers.com을 방문해 주십시오.

Don JonesTechNet Magazine의 객원 편집자이자 Windows PowerShell: TFM(SAPIEN Press)의 공동 저자입니다. Windows PowerShell(www.ScriptingTraining.com) 강사이기도 한 그는 ScriptingAnswers.com 웹 사이트를 통해 연락할 수 있습니다.

© 2008 Microsoft Corporation 및 CMP Media, LLC. All rights reserved. 이 문서의 전부 또는 일부를 무단으로 복제하는 행위는 금지됩니다..