Regex

regex 매칭은 ~ 연산자를 사용합니다. awk 에서 regex 를 작성하는 방법은 regex 상수 (/.../) 을 이용하는 방법과 스트링을 이용하는 방법 두 가지가 있습니다. 기본적으로 extended regular expression 을 사용하므로 regex 에서 사용하는 ?, +, ( ), { }, | 문자들을 escape 할 필요가 없습니다.

regex 상수 /.../ 를 이용하는 방법

  • ~ 연산자를 사용하지 않고 단독으로 사용할 수 있는데 그럴 경우 기본적으로 $0 과 매칭합니다.

  • 식 내에서 기본적으로 escape 문자가 처리됩니다.

  • / or \ 문자를 식에 사용하려면 escape 합니다.

  • regex 상수 라고도 하고 변수를 사용하지 못하는 단점이 있습니다.

# /.../ 에서 '\t' escape 문자가 처리되어 매칭이 된다.
$ echo -e '111\t222:333\t444' | awk -F: '$1 ~ /11\t22/ { print $1 }'
111    222

$ echo '/' | awk '///{ print }'        # ERROR

$ echo '/' | awk '/\//{ print }'       # OK
/

$ echo '\' | awk '/\/{ print }'        # ERROR

$ echo '\' | awk '/\\/{ print }'       # OK
\

$ echo '\' | awk '/[\]/{ print }'      # ERROR

$ echo '\' | awk '/[\\]/{ print }'     # OK
\

# '~' 연산자를 사용하지 않고 독립적으로 사용하면 기본적으로 '$0' 와 매칭을 합니다.
# 따라서 다음 예는 awk '$0 ~ /^foobar$/ ...' 와 동일합니다.
$ echo 'foobar' | awk '/^foobar$/ { print }'
foobar
$ echo 'foobar' | awk '{ if ( /^foobar$/ ) print }'
foobar

# 다음 두 식은 결과적으로 동일합니다.
# 매칭이 성공하여 값 1 이 AA 변수에 대입됩니다.
$ echo 'foobar' | awk '{ AA = /^foobar$/;  print AA }'
1
$ echo 'foobar' | awk '{ AA = ( $0 ~ /^foobar$/ );  print AA }'
1
# 매칭이 실패할 경우는 0 이 대입됨
$ echo 'foobar' | awk '{ AA = /^fooxxx$/;  print AA }'
0

스트링을 이용하는 방법

  • 스트링을 이용하면 regex 식 내에 변수를 사용할 수 있고 또한 regex 식 자체를 변수에 대입해 사용할 수도 있습니다.

  • 단독으로 사용할 수 없고 항상 ~ 연산자와 함께 사용해야 합니다.

  • 스트링을 이용하는 방법의 단점은 regex 상수에 비해 escape 처리가 복잡하다는 점입니다.

# 스트링을 이용하면 식 내에서 변수를 사용할 수 있습니다.
$ echo 'foobar' | awk '{ var = "ob"; if ( $0 ~ "^fo" var "ar$" ) print }'
foobar

# regex 식 자체를 변수에 넣어 사용할 수도 있습니다.
$ echo 'foobar' | awk '{ regex = "^foobar$"; if ( $0 ~ regex ) print }'
foobar

다음은 식을 작성할 때 regex 상수와 스트링의 차이점을 보여줍니다.
스트링으로 작성할 때는 /.../ 안에 들어가는 스트링과 동일하게 되도록 만들어준다고 생각하면 됩니다.

# regex 상수로 작성한 경우
$ echo '"111\222":"333\444"' | awk -F: '$1 ~ /"111\\222"/ { print $1 }'
"111\222"

# 동일한 식을 스트링으로 만들 경우
# 먼저 double quotes 은 " " 내에서 escape 해야 하므로 \" 로 작성하고
# '\\' 를 만들려면 '\' 문자는 escape 해야 하므로 '\\\\' 로 작성해야 합니다.
$ echo '"111\222":"333\444"' | awk -F: '$1 ~ "\"111\\\\222\"" { print $1 }'
"111\222"

Regular expression Extensions

sed 에서는 word boundary 와 관련해서 \b, \B 를 사용하는데 awk 에서는 \y, \B 를 사용합니다.
(\b 는 backspace escape 문자로 사용됩니다.)

소문자와 대문자가 같이 있는데 대문자는 소문자의 logical NOT 이라고 생각하면 됩니다.

\s, \S

\s[[:space:]]\S[^[:space:]] 를 나타냅니다.

\w, \W

\w[[:alnum:]_] 를 나타냅니다. 즉 [:alnum:] 클래스에 _ 가 추가된 것입니다.
(- 는 포함되지 않습니다.)

\W[^[:alnum:]_] 를 나타냅니다.

\y, \B

word boundary 를 나타냅니다.

# \y 의 경우
$ echo 'abc %-= _def.' | awk '{ gsub(/\y/,"X") }1'
XabcX %-= X_defX.

# \B 의 경우
$ echo 'abc %-= _def.' | awk '{ gsub(/\B/,"X") }1'
aXbXc X%X-X=X _XdXeXf.X

-------------------------------------------------

$ echo '*foo_bar' | awk '/\y[a-z]\w+/'
*foo_bar

$ echo '_foo_bar' | awk '/\y[a-z]\w+/'
$

\<, \>

\< 는 word boundary 인데 word 의 시작 부분을, \> 는 word 의 끝부분을 나타냅니다.

# '\<' 의 경우
$ echo 'abc %-= def.' | awk '{ gsub(/\</,"X") }1'
Xabc %-= Xdef.

# '\>' 의 경우
$ echo 'abc %-= def.' | awk '{ gsub(/\>/,"X") }1'
abcX %-= defX.

대, 소문자 구분 없이 매칭하기

regex 매칭은 기본적으로 대, 소문자를 구분하는데요 구분 없이 매칭을 하려면 다음과 같은 방법을 사용할 수 있습니다.

  • [ ] 을 이용하는 방법
# Foo, foo 모두 매칭이 된다.
$1 ~ /[Ff]oo/ { ... }
  • tolower 함수를 이용하는 방법
tolower($1) ~ /foo/ { ... }
  • IGNORECASE builtin 변수를 사용하는 방법

기본값은 0 인데 1 로 설정을 하게 되면 매칭시 대, 소문자 구분을 하지 않습니다. 이 방법을 사용할 때 주의할 점은 변수값 설정은 특정 블록에만 적용되는 것이 아니라 설정된 시점부터 awk 명령이 종료될 때까지 소스코드 전체에 적용된다는 점입니다.

x = "aB"
if (x ~ /ab/) ...   # 기본 설정은 대, 소문자를 구분하므로 fail!

IGNORECASE = 1
if (x ~ /ab/) ...   # succeed!