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

p016 Powershell에서 Regular Expression 사용하는 모든 방법

 ·  ☕ 4 min read

powershell에서는 regex를 사용하는 방법은 다양합니다. 기본적인 Select-String에서 Pester의 Should Match까지 살펴 보았습니다.

Select-String

이 cmdlet은 파일이나 문자열안에서 패턴을 찾는데 적합합니다.

원래 이런 형태로 쓰입니다만,

1
Select-String [-Pattern] <string[]> [-Path] <string[]> 

파이프를 이용하면 다음과 같이 사용할 수 있습니다.

1
Get-ChildItem -Path $logFolder | Select-String -Pattern 'Error'

이 예재는 $logFolder 디렉토리안의 파일중에 Error라는 문자열을 가지는 파일을 찾는 내용입니다. 이때 -Pattern 파라메터를 사용하면 다음과 같이 사용할 수 있습니다.

1
Get-ChildItem -Path $logFolder | Select-String -Pattern '\S{4}\d{4}'

-match

-match 연산자는 regular expression의 패턴에 일치하면 $true를 되돌립니다.

1
2
'123-45-6789' -match '\d\d\d-\d\d-\d\d\d\d'
True

만약 array에 이 연산자를 사용하면 match하는 라인만 보여줍니다. 이 부분이 리눅스의 grep에 해당하는 부분입니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
PS> $data = @(
    "General text without meaning"
    "my ssn is 123-45-6789"
    "some other string"
    "another SSN 123-12-1234"
    )
PS> $data -match '\d\d\d-\d\d-\d\d\d\d'

my ssn is 123-45-6789
another SSN 123-12-1234

로그 화일에서는 다음과 같이 사용할 수 있습니다.

1
(Get-Content weblog.txt) -match '2020/07/28'

Variations

  • -imatch 대소문자 가리지 않고 패턴을 검사합니다. -match와 동일합니다만 명시적 표현입니다.

  • -cmatch 대소문자 가려서 패턴을 검사합니다.

  • -notmatch 패턴과 일치하지 않을 경우 true를 돌립니다.

-like

일반적인 와일드카드의 *?를 사용한 패턴을 검사합니다.

이 연산자는 -ilike, -clike, -notlike 과 같은 variations가 있습니다.

String.Contains()

닷넷의 String 클래서의 멤버 Method입니다. 주어진 substring을 가지고 있는지 확인합니다.

-replace

문자열을 치환하는 이 연산자도 regex를 사용합니다.

이 연산자도 -creplace-ireplace 의 변형이 있습니다.

String.Replace()

닷넷의 이 연산자는 regex를 사용하지 않습니다.

-split

이 연산자도 regex를 사용합니다. 만일 . 문자를 사용하면 예상하지 않은 결과가 나올 수도 있습니다.

1
2
('CA.TX.NE' -split '.').count
9

이 연산자도 -isplit-csplit 의 변형이 있습니다.

String.Split()

역시 닷넷의 이 Method도 regex를 지원하지 않습니다.

Switch

자주 사용하지는 않습니다만, Switch 문에도 regex를 사용할 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
switch -regex ($message)
{
    '\d\d\d-\d\d-\d\d\d\d' {
        Write-Warning 'message may contain a SSN'
    }
    '\d\d\d\d-\d\d\d\d-\d\d\d\d-\d\d\d\d' {
        Write-Warning 'message may contain a credit card number'
    }
    '\d\d\d-\d\d\d-\d\d\d\d' {
        Write-Warning 'message may contain a phone number'
    }
}

ValidatePattern

함수를 선언할 때, [cmdletbinding()]을 이용하여 진보된 함수를 선언할 수 있습니다. 이 때 [ValidatePattern()]를 이용하여 regex validation을 줄 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function Get-Data
{
    [cmdletbinding()]
    param(
        [ValidatePattern('\d\d\d-\d\d-\d\d\d\d')]
        [string]
        $SSN
    )

    # ... #
}

ValidateScript

아주 복잡한 validation을 validator를 이용하여 구현하고 싶은 경우에 ValidateScript()을 이용할 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[ValidateScript({
    if( $_ -match '\d\d\d-\d\d-\d\d\d\d')
    {
        $true
    }
    else
    {
        throw 'Please provide a valid SSN (ex 123-45-5678)'
    }
})]

ValidatePattern ErrorMessage

Powershell 버전 6 부터는 ValidatePattern에 ErrorMessage를 전달할 수 있습니다.

1
[ValidatePattern('\d\d\d-\d\d-\d\d\d\d',ErrorMessage = 'The pattern does not match a valid US SSN format.')]    

변수에 Validator를 사용하기

함수의 파라메터 뿐만 아니라, 로직에서 일반 변수를 선언할 때도 Validator를 사용할 수 있습니다.

1
2
PS> [ValidatePattern('\d\d\d-\d\d-\d\d\d\d')]
PS> [string]$SSN = '123-45-6789'

자주 사용하진 않습니다만, 알아두어도 좋은 trick이라고 생각합니다.

$Matches

-match 연산자를 사용하면 자동으로 그 결과가 $Matches에 저장됩니다.

1
2
3
4
5
$message = 'My SSN is 123-45-6789.'

$message -match 'My SSN is (\d\d\d-\d\d-\d\d\d\d)\.'
$Matches[0]
$Matches[1]

Named matches

regex 에서 일치하는 결과에 이름을 붙이는 것도 가능합니다.

$message = 'My Name is Kevin and my SSN is 123-45-6789.'

if($message -match 'My Name is (?<Name>.+) and my SSN is (?<SSN>\d\d\d-\d\d-\d\d\d\d)\.')
{
    $Matches.Name
    $Matches.SSN
}

닷넷 Regex 클래스

1
[regex]::new($pattern) | Get-Member

간혹 [regex]::Escape()은 사용할 일이 있기는 합니다. powershell에 이를 대체할 수 있는 기능이 없습니다.

Escape regex

1
2
3
PS> $message = $message = 'My phone is (123)456-7890'
PS> $message -match '(123)456-7890'
False
1
2
PS> $message -match [regex]::Escape('(123)456-7890')
True

하나의 line에 Multiple matches

Select-String는 하나의 라인에 지정한 패턴이 여러개 발견되면 모두를 Object로 리턴하는 -AllMatches 파라메터를 가지고 있습니다.

1
2
3
4
5
6
7
PS> $data = 'The event runs from 2018-10-06 to 1018-10-09'
PS> $datePattern = '\d\d\d\d-\d\d-\d\d'
PS> $results = $data | Select-String $datePattern -AllMatches
PS> $results.Matches.Value

2018-10-06
2018-10-09

Regex Matches()

닷넷의 Regex 클래스도 Matches 라는 Method를 가지고 있습니다.

1
2
3
4
5
6
7
PS> $data = 'The event runs from 2018-10-06 to 1018-10-09'
PS> $datePattern = [Regex]::new('\d\d\d\d-\d\d-\d\d')
PS> $matches = $datePattern.Matches($data)
PS> $matches.Value

2018-10-06
2018-10-09

Pester의 Should match

유닛테스트 모듈인 Pester의 Should Match 도 regex를 사용합니다.

1
2
3
4
It "contains a SSN"{
    $message = Get-Data
    $message | Should Match '\d\d\d-\d\d-\d\d\d\d'
}

레퍼런스

공유하기

tkim
글쓴이
tkim
Software Engineer