Regular expression in sed
Programmingsed(1) 에서 사용되는 정규표현식에 대해서 알아보기 위해 Overview of Regular Expression Syntax 의 내용을 옮겨본다.
sed 를 잘 쓰기 위해서는 정규표현식(regexp)을 잘 알아야 한다. 정규표현식이란 주어진 문자열(subject string)에서 왼쪽에서 오른쪽으로 봐가면서 매칭되는 패턴을 의미한다. 정규표현식에서 대부분의 문자들(character)은 일반문자(ordinary)이다. 즉 이 문자들이 패턴 자체이고 주어진 문자열에서 해당 문자들이 나올 경우 매칭되게 된다. 예를 들어 아래와 같은 패턴은,
The quick brown fox
그 자체가 패턴이 된다. 하지만 정규표현식의 강력한 기능은 패턴을 작성함에 있어서 대치(alternatives)와 반복(repetitions)이 가능하다는 점이다. 정규표현식에서 대치와 반복은 특수문자를 써서 표현할 수 있다. 이렇게 특수문자로 쓰인 패턴은 그 자체가 패턴이 되는 것이 아니라 뭔가 특별한 용도를 위해 다르게 처리된다. 그럼 아래에 sed 에서 쓰이는 정규표현식 문법에 대해 정리해 보겠다.
Pattern | Meaning |
---|---|
char | 그 자체가 패턴이 되는 일반문자를 나타냄. |
* | * 앞에 나오는(preceding) 정규표현식이 0번 이상 매칭되는 패턴을 의미한다. '앞에 나오는 정규표현식'에는 ①일반문자, ②백슬래시(\)로 시작하는 특수문자, ③점(.), ④(아래에서 설명할)정규표현식 그룹, 그리고 ⑤대괄호로 묶여진 표현식 등이 될 수 있다. GNU 확장규칙(extension) 에서는 정규표현식이 * 뒤에서 나올(postfixed)수도 있다. 예를 들어, a** 은 a* 랑 같다. POSIX 1003.1-2001에 의하면 * 은 어떤 정규표현식이나 서브익스프레션의 시작부분에 등장할 경우 별(*) 그 자신을 의미한다고 되어있다. 하지만 많은 non-GNU 유틸들은 이를 지원하지 않으며, 같은 상황에서 포터블 스크립트들은 \* 을 대신 사용한다. |
\+ | * 과 동일하지만 매칭되는 패턴의 개수가 1개 이상이다. GNU extension. |
\? | * 과 동일하지만 매칭되는 패턴의 개수가 0 또는 1개 이다. GNU extension. |
\{i\} | * 과 동일하지만 매칭되는 패턴의 개수는 정확히 i 번이다. 여기서 i는 10진수 정수지만 0~255 사이의 값을 사용하는것이 안전하다. |
\{i,j\} | i에서 j 개가 매칭된다. |
\{i,\} | i 번 이상 매칭된다. |
\(regexp\) |
내부 regexp를 그룹지을 때 사용한다. 그룹이 사용되는 예를 살펴보면 아래와 같다.
|
. | 개행을 포함한 모든 캐릭터와 매칭된다. |
^ |
어떤 패턴에서 시작 부분의 널문자와 매칭된다. 이게 무슨 말이냐면,
꺾쇄문자(^) 다음에 오는 패턴은 패턴의 시작부분이라는 얘기다.
대부분의 sed 스크립트에서 패턴은 새 행이 시작될 때마다 초기화된다. 따라서 ^#include 의 경우 해당 행은 '#include' 라는 문자열로 시작되어야 하는 것이다. 만일 '#include' 앞에 공백이 있는 행일 경우에는 패턴매칭이 실패한다. 또한 이는 패턴 스패이스에서 원본 컨텐츠가 수정되지 않은 경우, 예를 들어 s 커맨드를 사용할 경우에만 유효하다. ^는 정규표현식이나 서브익스프레션에서 맨 앞에 나오는 특수문자로서도 쓰일 수 있다. POSIX에서 ^를 일반문자로 취급하는것을 허용하기는 하지만 포터블 스크립트에서는 서브익스프레션의 시작부분에 ^를 사용하는 것을 피하는 것이 좋을 것이다. |
$ | ^ 와 비슷하지만 맨 끝부분 패턴을 나타낸다. $ 도 역시 정규표현식이나 서브익스프레션에서 맨 끝에있는 특수문자를 가리키는데 쓰일 수 있다. |
[list] [^list] |
list 내부의 단일 문자와 매칭된다.
예를 들어, [aeiou] 은
모든 모음 문자(vowels)와 매칭된다.
list는 char1-char2와 같은 표현식
(char1 과 char2사이에 있는 모든 단일 캐릭터)
으로도 사용할 수 있다.
여기서 맨 앞에 ^이 나올 경우 list의 의미를 반전시킨다. 즉, list안에 있는 문자들을 제외한 단일 문자가 된다. 이스케이핑(escape) 관련하여 특수문자인 ] 을 list 안에 포함시키기 위해서는 대괄호 닫음(])을 맨 처음에 넣으면 되고(^가 필요할 경우 ^를 먼저 넣는다), 특수문자 - 를 list 안에 넣기 위해서는 대시(-)를 맨 처음이나 맨 나중에 넣는다. 특수문자 ^ 의 경우에는 첫 문자 다음에 넣도록 한다. 특수문자 $, *, ., [, \ 들은 list 안에서 특수문자(특별한의미)로 동작하지 않는다. 예를 들어 [\*] 이것은 '\' 이나 '*' 문자가 매칭된다. 왜냐하면 \ 은 list 안에서 특수문자(특별한의미)로 동작하지 않기 때문이다. 그렇지만 [.ch.], [=a=], [:space:] 들은 list 안에서 그별한 의미를 지니며 각각은 ch 이중문자(collating symbol; ch 체코어?), a 와 동등한 정렬순서를 갖는 문자집합(equivalence class), 공백을 나타내는 문자클래스(character class)를 의미한다. 즉, [ 는 list 안에서 ., =, : 등과 함께 쓰였을 경우 특별한 의미를 갖게된다. 또한 POSIXLY_CORRECT 모드가 아닐 경우 \n 이나 \t 과 같은 특수문자들도 list 안에서 특별한 의미를 갖는다. Escape 참고. |
regexp1\|regexp2 | regexp1 이나 regexp2 를 매칭한다(OR). 소괄호()를 사용하면 여러개를 이어서 사용할 수도 있는 것 같다. 매칭 과정은 왼쪽부터 시작해서 오른쪽으로 가면서 정규표현식들을 검사하고, 제일 처음 매칭된 정규표현식을 사용하게 된다. GNU extension 이다. |
\digit | 정규표현식 안에서 digit 번째의 소괄호 \(...\) 로 둘러싸인 서브익스프레션과 매칭된다. 이것을 back reference 라고 한다. 서브익스프레션은 암묵적으로 왼쪽에서 오른쪽으로 보면서 \( 이것이 나온 개수에 대하여 넘버링이 되어있다. |
\n | 개행 문자와 매칭된다. |
\char | char 와 매칭한다. 여기서 char는 $, *, ., [, \, ^ 이들 중에 하나이다. 이스케이핑(escape) 용도라는 말임. 참고로 C언어에서의 백슬래시 조합 특수문자 중에 \n 이나 \\ 이런것은 사용할 수 있다. 하지만 \t 는 대부분의 sed 구현에서 빠져있다. 즉, 탭 문자가 아니라 t로 매칭을 시도하게 된다. |
정규표현식의 매칭방식은 좌에서 우로 나아가며 매칭하고, 같은 위치에서 두 개 이상의 매칭이 발견되었을 경우에는 긴 쪽을 택한다. 그래서 greedy(탐욕스러운) 하다라고도 한다.
아래는 정규표현식 예제들이다.
- 'abcdef'
- 쓰여진 그대로 'abcdef' 와 매칭됨.
- 'a*b'
- 0개 이상의 'a'와 그 다음에 'b'가 나오는 경우와 매칭된다. 예를 들면 'b'나 'aaaaab'.
- 'a\?b'
- \? 는 0개 또는 1개 와 매칭되는 것이다. 따라서 'b' 또는 'ab' 와 매칭된다.
- a\+b\+
- \+ 는 1개 이상과 매칭되는 것이다. 따라서 1개 이상의 'a'와 이어서 1개 이상의 'b'가 오는 경우이다. 가장 짧게 매칭되는 경우가 'ab' 이고 'aaaab', 'abbbbb', 'aaaaaabbbbbb' 이렇게도 가능하다.
- '.*/
'.\+' - 둘 다 모든 캐릭터 문자열과 매칭되는 경우이다. 단, 위의 케이스는 널 스트링을 포함한 모든 문자열과 매칭되지만, 아래것은 최소한 하나의 문자는 들어있는 문자열과 매칭된다.
- '^main.*(.*)'
- 'main'으로 시작하고, 소괄호로 둘러쌓인 문자열이 이어지는 경우이다. 'n'과 '('과 ')' 이 위치가 반드시 딱 붙어있어야 하는것은 아니다.
- '^#'
- '#'으로 시작하는 문자열과 매칭된다.
- \\$
- 백슬래시(\) 하나로 끝나는 문자열과 매칭된다. 백슬래시를 두 개 썼지만 하나는 escaping 용도로 쓴 것이다.
- '\$'
- 달러 기호 하나와 매칭된다. 여기에 쓰인 백슬래시도 escaping 용도로 쓰였다.
- '[a-zA-Z0-9]'
- 환경변수 로케일이 C locale 인 경우, 모든 ASCII 문자 혹은 숫자와 매칭된다.
- '[^ tab]\+
- 여기서 tab 은 탭 문자이다. 이 예제는 공백이나 탭 문자를 제외한 한 글자 이상의 캐릭터와 일치한다. 즉, 한 단어(word)를 의미한다.
- '^\(.*\)\n\1$'
- \(regexp\) 은 그룹을 이루고 back reference 로도 쓰인다. 이 예제는 두 개의 동일한 문자열 사이에 개행문자가 하나 들어간 꼴이다.
- '.\{9\}A$'
- 9개의 문자에 이어서 A가 나오는 패턴이다.
- '^.\{15\}A'
- 16개의 문자로 시작하고, 그 16개 중에 마지막 문자가 A인 경우이다.
'Programming' 카테고리의 다른 글
Bash에서 문자열 검색 조건식 만들기 (0) | 2018.07.22 |
---|---|
Truncate PWD in prompt (MacOS) (0) | 2018.04.29 |
How to terminate a background process (0) | 2018.04.24 |
macOS에 emacs ggtags 설치 및 설정 (0) | 2017.10.17 |
Xcode에 assimp 올리기 (0) | 2017.06.06 |