델리미터(Delimeter)로 컬럼이 분기된 텍스트 파일(보통은 아마도 로그파일)을 다룰 때 가장 손쉽게 쓸 수 있는 도구가 awk 입니다. 물론 cut 등도 있지만 탐색한 이후의 작업을 주로 담당하기 때문에 탐색시에는 역시 awk 가 대세입니다. (당연하겠습니다만 awk 도 정규표현식의 탐색을 지원하니 자세한 내용은 글 맨 아래의 포스팅 링크를 참고해 주세요.)
awk 에서 특정 컬럼의 값을 표현하는 방법은 여러가지가 있습니다. 그동안 많이 사용했던 패턴은 아래와 같은 방식이었는데요 이 방식에서도 or, and 조건을 사용하는 것은 문제가 없습니다. 조건을 동시에 만족하는 경우를 찾으려면 &&를, 어느 하나라도 만족하는 경우를 찾으려면 || 를 사용하면 됩니다.
// AND (&&)
awk '$2=="" && $19~/my/ {print $11, $24}'
// OR (||)
awk '$2=="" || $19~/my/ {print $11, $24}'
이렇게 표현하는 방법 외에 브레이스({}) 안쪽에 if 문을 넣어서 사용하는 방법도 있습니다. 어느 방법을 사용하던 원하는 결과를 얻을 수 있으면 되니 손에 더 감기는 방법을 사용하면 좋을 것 같습니다. NOT 조건을 사용하는 경우에도 보다 쉽고 명시적으로 읽을 수 있어서 이 방법을 개인적으로는 선호하는 편입니다.
// AND (&&)
awk '{ if ($5=="/test" && $3=="GET") print $0}'
// OR (&&)
awk '{ if ($5=="/test" || $5=="/beta") print $0}'
// NOT (!)
awk '{ if (!($5=="/test")) print $0}'
쉘에서 로그와 같은 텍스트 파일을 다룰때 정규표현식을 자주 사용하게 됩니다. 정규표현식을 지원하는 쉘의 도구들은 여러가지가 있는데요 오늘은 awk 에서 정규표현식을 사용하는 방법을 간단하게 살펴보겠습니다.
// 일반적인 awk 의 사용 : 첫번째 컬럼 값이 server 인 경우 행($0)을 그대로 출력
$ cat my.log | awk '$1="server" { print $0 }'
// 정규표현식을 만족하는 행 찾기 (Positive Match) : /beta/
$ cat my.log | awk '/\/beta\// { print $0 }'
// 정규표현식을 만족하지 않는 행 찾기 (Negative Match) : /beta/ 가 아닌 경우
$ cat my.log | awk '!/\/beta\// { print $0 }'
일반적으로 awk 는 독립적으로 사용되지 않고 cat 과 같은 다른 명령과 파이프(|)로 연결해서 문자열을 다룹니다. 위 코드의 첫번째 예시는 awk 가 델리미터 단위로 행을 분할해주는 기능을 이용하여 첫번째 컬럼($1)의 값이 만족하는 경우 해당 행을 출력하는 명령입니다.
정규표현식을 이용하려면 슬래시로 정규 표현식 문자열을 넣어주면 됩니다. 가령 URL 에 /beta/ 라는 path 가 존재할 수 있고, 해당 항목이 있는 경우만 출력한다면 \/beta\/ 로 표현식을 만들면 됩니다. 두번째 예시를 참고하시면 되겠습니다.
정규표현식을 만족하지 않는 Negative Match 로 자료를 찾아야 하는 경우도 있습니다. 이때는 정규 표현식을 감싸고 있는 슬래시의 앞에 느낌표(!)를 붙여주기만 하면 됩니다.
터미널에서 로그파일을 핸들링하면서 자주쓰이는 명령들이 있습니다. 전체 파일을 출력하기 위해서 cat 명령을 사용하고 특정한 컬럼의 값만 출력하기 위해서 파이프로 연결된 awk 명령을 쓸 때가 많습니다. 그런데, 컬럼이 아주 많은 경우에 특정한 컬럼만 제외하고 나머지를 출력할 수 있는 방법이 있을까요? 컬럼이 적은 경우에는 필요한 필드를 나열하는 것도 괜찮지만, 수십개, 수백개의 컬럼이 있다면 그다지 좋은 방법이 될 수가 없습니다.
예를 들어 temp.txt 파일에 아래와 같이 스페이스로 구분된 10개의 컬럼이 있다고 해보겠습니다. 이 파일의 정보들 중에서 특정한 컬럼의 값만 추출하고 싶다면 awk 명령을 이용해서 print 예약어를 이용할 수 있을 겁니다.
$ cat temp.txt
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10
$
$ cat temp.txt | awk '{print $3, $5}'
C3 C5
이 데이터 파일에서 거꾸로 3번 컬럼과 5번 컬럼의 값을 제외한 나머지 컬럼의 값을 추출하려면 어떻게 해야 할까요? print 구문의 파라메터로 $3 과 $5 만 빼고 나열해도 되겠지만, 아래와 같이 명령을 입력하면 훨씬 빠르고 쉽게 특정한 컬럼만을 제외하고 데이터를 정제할 수 있게 됩니다.
$ cat temp.txt | awk '{$3=$5=""; print $0}'
C1 C2 C4 C6 C7 C8 C9 C10
동일한 결과물을 얻어내는 방법이 여러가지 있다면 그중에서 가장 간편한 방법을 택하는 것이 누가 뭐라해도 진리일 겁니다. 작업시간을 절약하고 더 집중해야 하는 것들에 몰입하는 하루 되시길 바랍니다!