[쉘 스크립트] 쉘 스크립트 기초 - 정규표현식 (8)
카테고리: Linux
태그: Linux
🎯정규표현식
정규표현식은 리눅스 유틸리티가 텍스트를 걸러내는 데 사용하는 정의 템플릿이다. 리눅스 유틸리티(이를테면 sed 편집기나 gawk 프로그램)는 유틸리티에 데이터가 들어오면 정규표현식 패턴과 댖도하여 데이터 패턴과 일치하면 처리되고 일치하지 않으면 처리는 거부된다.
정규표현식은 와일드카드 패턴과 비슷한 방식으로 동작한다. 정규표현식 패턴은 sed 편집기 및 gawk 프로그램이 데이터 대조를 위해 따라야 하는 템플릿을 정의하는 텍스트와 특수문자를 포함한다. 데이터 필터링의 특정한 패턴을 정의하기 위해 정규표현식에서 다양한 특수 문자를 사용할 수 있다.
정규표현식 엔진
리눅스 세계에는 두 객의 인기 있는 정규표현식 엔진이 있다.
- POSIX 기본 정규표현식(BRE) 엔진
- POSIX 확장 정규표현식(ERE) 엔진
대부분의 리눅스 유틸리티는 최소한 POSIX BRE 엔진 제원을 준수하며, 여기에 정의된 모든 기호를 인식한다. 하지만 BRE 엔진 제원의 일부만을 준수하는 유틸리티(sed 편집기)도 있다. 이는 속도문제 때문인데 sed 편집기는 될 수 있는대로 빨리 데이터 스트림에서 텍스트를 처리하려고 시도하기 때문이다.
POSIX ERE 엔진은 텍스트 필터링을 정규표현식에 의존하는 프로그래밍 언어에서 볼 수 있다. 여기서는 숫자, 단어 및 영숫자와 같은 일반적인 패턴을 위한 특수 기호뿐만이 아니라 고급 패턴 기호도 제공한다. gawk 프로그램은 ERE 엔진을 사용하여 정규표현식 패턴을 처리한다.
BRE 패턴
일반 텍스트
- 정규표현식이 데이터 스트림의 어디에서 발생하는지는 중요하지 않다. 또한 패턴이 발생하는 횟수도 중요하지 않다. 텍스트 문자열의 아무 곳에서나 패턴과 일치되는 것을 발견할 수 있다.
- 정규표현식 패턴은 대소문자를 구분한다.
- 정규표현식 패턴에 한 개의 문자 단어만 쓰라는 법은 없다. 패턴에는 빈 칸 및 숫자를 포함할 수 있다.
- 빈 칸은 정규표현식에서 하나의 문자처럼 간주된다.
$ echo "The books are expensive" | sed -n '/book/p'
The books are expensive
$ echo "This is a test" | sed -n '/this/p'
$ echo "This is a test" | sed -n '/This/p'
This is a test
$ echo "This is line number 1" | sed -n '/ber 1/p'
This is line number 1
특수 문자
정규표현식에서 텍스트 문자를 정의할 때에는 몇 가지 예외가 있다. 다음의 문자는 정규표현식에서 특별한 의미를 가진다. 이러한 문자는 텍스트 패턴에서 문자 그대로 사용할 수 없다.
.*[]^${}\+?#
- 특수 문자 중 하나를 텍스트 문자처럼 사용하려고 하면 이스케이프시켜야 한다. 이러한 기능을 하는 특수 문자는 백슬래시 문자 다
- 백슬래시는 특수 문자이기 때문에 문자 자체를 패턴 매칭하려면 백슬래시 자체도 이스케이프 시켜야 한다.
- 일반 슬래시는 정규표현식 특수 문자는 아니지만 sed 편집기나 gawk 프로그램에서 정규표현식 패턴 안에 사용하면 오류가 난다. 슬래시를 사용하려면 이스케이프 처리해야 한다.
캐럿 문자
- 캐럿 문자(^)는 데이터 스트림 안의 텍스트 줄 맨 처음에서 시작하는 패턴을 정의한다.
- 캐럿 문자는 새로운 각 줄의 시작 부분에서만 패턴을 확인한다.
- 패턴의 시작 부분이 아닌 다른 곳에 캐럿 문자를 두면 특수 문자가 아닌 보통 문자로 인식한다.
$ echo "The book store" | sed -n '/^book/p'
$ echo "Books are great" | sed -n '/^Book/p'
Books are great
$ cat <<EOF | sed -n '/^this/p'
This is a test line
this is another test line.
A line that tests this feature
Yer more testing of this
EOF
this is another test line.
$ echo "This ^ is a test" | sed -n '/s ^/p'
This ^ is a test
달러 기호
줄의 시작에서 패턴을 찾는 캐럿 기호와 반대로 줄의 마지막에서 찾는 방법도 있다. 달러 기호($) 특수 문자는 데이터 줄이 지정된 텍스트 패턴으로 끝나는지 검사한다.
$ echo "This is a good book" | sed -n '/book$/p
'
This is a good book
$ echo "This book is good" | sed -n '/book$/p'
캐럿 문자와 달러 기호 결합하기
- 지정된 텍스트를 포함한 줄에 대해서만 패턴 매칭하는데 사용할 수 있다.
- 텍스트가 없는 빈 줄을 걸러내는 데 사용할 수 있다.
$ cat <<EOF | sed -n '/^this is a test$/p'
this a test of using both anchors
I said this is a test
this is a test
EOF
this is a test
$ cat <<EOF | sed '/^$/d'
This is one test line
This is another test line.
EOF
This is one test line
This is another test line.
점 문자
점 특수 문자는 줄바꿈 문자를 제외한 모든 문자 한 개와 일치시키기 위해 사용된다. 점의 위치에 어떤 문자도 없다면 패턴은 실패한다. (정규표현식에서는 빈 칸도 글자로 간주한다는 점을 상기하자)
$ cat <<EOF | sed -n '/.at/p'
This is a test of a line
The cat is sleeping
That is a very nice hat
This test is at line four
at ten 0'clock we'll go home
EOF
The cat is sleeping
That is a very nice hat
This test is at line four
문자 클래스
사용자는 텍스트 패턴의 어떤 위치에서 대조할 문자의 클래스를 정의할 수 있다. 문자 클래스의 문자 중 하나가 데이터 스트림에 있다면 패턴은 일치한다. 문자 클래스와 일치하는 문자가 없으면 매칭은 실패한다.
- 문자 클래스를 정의하려면 대괄호를 사용한다. 대괄호는 클래스에 들어갈 문자를 포함해야 한다.
- 하나의 표현식에서 클래스를 두 개 또는 그 이상 사용할 수 있다.
- 문자 클래스는 문자만 포함해야 하는 것은 아닌다. 숫자도 사용할 수 있다.
$ echo "Yes" | sed -n '/[Yy]es/p'
Yes
$ echo "yes" | sed -n '/[Yy]es/p'
yes
$ echo "Yes" | sed -n '/[Yy][Ee][Ss]/p'
Yes
$ echo "yEs" | sed -n '/[Yy][Ee][Ss]/p'
yEs
$ echo "yeS" | sed -n '/[Yy][Ee][Ss]/p'
yeS
$ cat <<EOF | sed -n '/[0123]/p'
This line doesn't contain a number
This line has 1 number on it.
This line a number 2 on it
This line has a number 4 on it.
EOF
This line has 1 number on it.
This line a number 2 on it
부정형 문자 클래스
문자 클래스의 효과를 뒤집을 수도 있다. 클래스에 포함된 문자를 찾는 대신 클래스에 없는 모든 문자를 찾을 수 있다. 이를 위해서는 문자 클래스 시작 부분에 캐럿 문자를 놓으면 된다. 이때의 캐럿 문자는 부정의 의미를 갖는다.
$ echo "Yes" | sed -n '/[Yy]es/p'
Yes
$ echo "Yes" | sed -n '/[^Yy]es/p'
문자 클래스 범위
사용자는 대시 기호를 이용하여 문자 클래스 안에서 문자 범위를 사용할 수 있다. 첫 번째 문자, 대시, 마지막 문자를 지정하면 된다. 정규표현식은 리눅스 시스템에서 사용되는 문자 집합에 따라 지정된 문자 범위 안에 있는 모든 문자를 포함한다.
$ cat <<EOF | sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p'
60633
46210
223001
4353
EOF
60633
46210
Note:
하나의 문자 클래스에 여러 개의 비연속 범위를 지정할 수도 있다.[a-ch-m]이러한 패턴은 a에서 c, h에서 m 범위를 수용한다. d와 g 사이에 있는 모든 문자는 매칭 실패된다.
특수 문자 클래스
사용자가 문자 클래스를 정의하는 것 말고도 BRE는 문자의 특정 유형과 대조할 때 쓸 수 있는 특수 문자 클래스를 포함하고 있다.
| 클래스 | 설명 |
|---|---|
| [[:alpha:]] | 대문자든 소문자든 모든 알파벳 글자와 일치한다. |
| [[:alnum:]] | 영숫자 및 문자 0-9, A-Z 또는 a-z와 일치한다. |
| [[:blank:]] | 빈 칸이나 탭 문자와 일치한다. |
| [[:digit:]] | 0에서 9까지의 숫자와 일치한다. |
| [[:lower:]] | 모든 소문자 알파벳 문자 a-z와 일치한다. |
| [[:print:]] | 인쇄할 수 있는 모든 문자와 일치한다. |
| [[:punct:]] | 문장 부호 문자와 일치한다. |
| [[:space:]] | 모든 화이트스페이스 문자와 일치한다. 즉, 빈 칸, 탭, NL, FF, VT, CR 문자다. |
| [[:upper:]] | 모든 대문자 알파벳 문자 A-Z와 일치한다. |
$ echo "abc" | sed -n '/[[:digit:]]/p'
$ echo "abc" | sed -n '/[[:alpha:]]/p'
abc
별표 문자
글자 다음에 별표를 놓으면 대조하는 텍스트에서 그 글자가 0번 또는 그보다 많이 나와야 한다.
- 별표 문자와 점 문자를 조합하면 어던 문자가 몇 개든 나와도 일치하는 패턴을 제공한다.
- 별표는 또한 문자 클래스에도 적용될 수 있다. 텍스트에 한 번 이상 나타날 수 있는 문자 그룹 또는 범위를 지정할 수 있다.
$ echo "ik" | sed -n '/ie*k/p'
ik
$ echo "iek" | sed -n '/ie*k/p'
iek
$ echo "ieek" | sed -n '/ie*k/p'
ieek
$ echo "ieeek" | sed -n '/ie*k/p'
ieeek
$ echo "bt" | sed -n '/b[ae]*t/p'
bt
$ echo "bat" | sed -n '/b[ae]*t/p'
bat
$ echo "bet" | sed -n '/b[ae]*t/p'
bet
$ echo "baat" | sed -n '/b[ae]*t/p'
baat
$ echo "baet" | sed -n '/b[ae]*t/p'
baet
$ echo "baaeet" | sed -n '/b[ae]*t/p'
baaeet
ERE 패턴
POSIX ERE 패턴은 일부 리눅스 응용 프로그램 및 유틸리티에 사용되는 몇 가지 추가 기호를 포함한다. gawk 프로그램은 ERE 패턴을 인식하지만 sed 편집기는 인식하지 못한다.
Note:
sed 편집기와 gawk 프로그램은 정규표현식 엔진이 다르다는 것을 기억하자. gawk 프로그램은 확장 정규식 패턴 기호 대부분을 사용할 수 있으며, sed 편집기에는 없는 추가 필터링 기능을 제공한다. 그 때문에 gawk 프로그램은 데이터 스트림 처리가 느려진다.
물음표 문자
물음표는 그 앞에 있는 문자가 없건가 한 번 나타나는 것을 뜻한다. 문자가 2번 이상 나타나는 것과는 일치하지 않는다.
$ echo "bt" | gawk '/be?t/{print $0}'
bt
$ echo "bet" | gawk '/be?t/{print $0}'
bet
$ echo "beet" | gawk '/be?t/{print $0}'
더하기 문자
더하기 기호는 앞의 문자가 한 번 이상 나타날 수 있지만 한 번 이상은 있어야 한다는 뜻이다. 문자가 아예 없으면 패턴은 일치하지 않는다.
$ echo "beet" | gawk '/be+t/{print $0}'
beet
$ echo "bet" | gawk '/be+t/{print $0}'
bet
$ echo "bt" | gawk '/be+t/{print $0}'
중괄호 문자
ERE에서 사용할 수 있는 중괄호는 제한적으로 정규표현식을 되풀이 할 수 있는데 인터벌이라고 한다. 두 가지 형식으로 인터벌을 표현할 수 있다.
- m: 정규표현식이 정확히 m번 나타남.
- m,n: 정규표현식이 적어도 m번 나타나지만 n번보다 많이 나타나지는 않음
Note:
기본적으로 gawk 프로그램은 정규표현식의 인터벌을 인식하지 못한다. gawk 프로그램이 정규표현식의 인터벌을 인식하도록 하려면--re-interval커맨드라인 옵션을 지정해야 한다.
$ echo "bt" | gawk --re-interval '/b[ae]{1}t/{print $0}'
$ echo "bat" | gawk --re-interval '/b[ae]{1}t/{print $0}'
bat
$ echo "bet" | gawk --re-interval '/b[ae]{1}t/{print $0}'
bet
$ echo "bat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bat
$ echo "bet" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bet
$ echo "baat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
baat
$ echo "baaat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
파이프 문자
파이프는 데이터 스트림을 검사할 때 정규표현식 엔진이 논리 OR 식에 사용할 두 개 또는 그 이상의 패턴을 지정할 수 있다. 패턴 중 어느 것이든 데이터 스트림의 텍스트와 일치한다면 텍스트는 패턴 일치를 통과한다. 패턴 중 어느 것도 일치하지 않는다면 매칭이 실패한다.
$ echo "The cat is asleep" | gawk '/cat|dog/{pr
int $0}'
The cat is asleep
$ echo "The dog is asleep" | gawk '/cat|dog/{print $0}'
The dog is asleep
$ echo "The rabbit is asleep" | gawk '/cat|dog/{print $0}'
표현식 그룹화
정규식 패턴은 또한 괄호로 그룹화할 수 있다.
$ echo "Sat" | gawk '/Sat(urday)?/{print $0}'
Sat
$ echo "Saturday" | gawk '/Sat(urday)?/{print $0}'
Saturday
📖출처
리처드 블룸, 크리스틴 브레스, ⌜리눅스 커맨드라인 쉘 스크립트 바이블⌟, 스포트라잇북(2016)
👍 개인 공부 기록용 블로그입니다. 오류나 조언이 있으시면 언제든지 댓글 혹은 메일로 남겨주시면 감사하겠습니다! 😄
댓글남기기