[Linux 셸 스크립트] 텍스트 처리 - 076 로그 파일 컬럼 위치를 바꿔서 출력하고 보기 쉽게 바꾸기
본문 바로가기
IT 이야기/Linux 셸 스크립트

[Linux 셸 스크립트] 텍스트 처리 - 076 로그 파일 컬럼 위치를 바꿔서 출력하고 보기 쉽게 바꾸기

by 찬찬이 아빠 2021. 4. 12.
반응형
  1. 사용 명령어

(1) awk

 

  2. 키워드 & 사용처

(1) 키워드

접속 로그, 로그 해석, 변형

 

(2) 사용처

아파치 접속 로그에서 필요한 컬럼을 추출하고, 순서를 바꾸고 싶을 때 사용합니다.

 

  3. 실행 예제
$ cat access_log
xx.xx.xx.xx - - [09/Apr/2021:12:20:20 +0900] "GET / HTTP/1.1" 200 83 "-" "-"
yy.yy.yy.yy - - [09/Apr/2021:13:21:33 +0900] "GET /index.html HTTP/1.1" 200 304
zz.zz.zz.zz - - [09/Apr/2021:12:22:12 +0900] "GET /title.gif HTTP/1.1" 200 763

$ ./log-column.sh access.log

# 로그 파일에서 시각과 원격 호스트를 추출해서 순서를 바꿔서 출력
$ cat access_log.lst
[09/Apr/2021:12:20:20 +0900] xx.xx.xx.xx
[09/Apr/2021:13:21:33 +0900] yy.yy.yy.yy
[09/Apr/2021:12:22:12 +0900] zz.zz.zz.zz

 

 

  4. 스크립트

#!/bin/sh

 

# 로그 파일이 존재하지 않으면 종료

if [ ! -f "$1" ]; then               

    echo "대상 로그파일이 존재하지 않습니다: $1" >&2                 

    exit 1             

fi

 

# 요청 시각과 원격 호스트를 외부 파일에 출력

awk '{print $4,$5,$1}' "$1" > "${1}.lst"             

 

 

  5. 해설

이 스크립트는 아파치 접속 로그에서 필요한 열을 추출해서 순서를 바꿔서 출력합니다. 로그 해석은 같은 조건으로 대량의 파일에서 추출할 때가 많으므로 이런 스크립트로 일괄 처리할 수 있습니다.

 

아파치는 접속 로그를 원하는대로 변경할 수 있으므로 실행예제에서 다루는 로그 형식과 실제 환경에서 작성된 로그는 조금씩 다를 수 잇습니다. 여기에서 사용하는 접속 로그는 일반적으로 사용하는 common이라는 설정을 사용합니다.

 아파치 common 형식 로그는 아래와 같습니다.

192.168.1.1 - - [12/Apr/2021:16:47:43 +0900] "GET /index.html HTTP/1.1" 200 83

로그의 항목별 의미는 다음과 같습니다.

의미 예제
원격 호스트 192.168.1.1
identd의 원격 사용자명 -
인증의 원격 사용자명 -
리퀘스트 받은 시각 [12/Apr/2021:16:47:43 +0900]
리퀘스트 첫 줄 "GET /index.html HTTP/1.1"
HTTP 스테이터스 200
레스폰스 바이트 수 83

'identd 원격 사용자명'은 mod_ident라는 아파치 모듈에서 제공합니다. 아파치에서 identd로 사용자명을 취득하는 경우는 거의 없으므로 대부분 "-"이 출력됩니다.

 

'인증 원격 사용자명'은 BASIC 인증 등에서 입력된 사용자명입니다. 인증이 없는 페이지는 단순히 "-"이 됩니다.

 

'리퀘스트 첫  줄'은 "HTTP메서드명 리퀘스트URI(파일명) HTTP버전"이 됩니다. 브라우저에서 웹 페이지를 볼 때 이런 리퀘스트 명령행을 직접 볼 일은 거의 없지만 내부적으로 웹 브라우저 웹 서버에 대해 이런 리퀘스트를 발행해서 웹 페이지를 취득합니다.

 

예제에서는 이런 로그를 바탕으로 파일명이 (로그 파일명).lst인 파일에 첫 번째 컬럼은 리퀘스트 시각, 두 번째 컬럼은 원격 호스트로 출력된다고 가정합니다.

 

우선 스크립트에서 인수로 로그 파일명을 받으므로 에서는 명령행 인수를 확인하고 파일 존재 여부를 알아봅니다. -f는 일반 파일인지 확인하는 연산자로 부정 연산자 !와 함께 써서, 일반 파일이 아닐 때 에러를 출력하고 종료합니다.

 

는 로그 파일에서 awk 명령어로 필요한 열을 추출합니다. awk 명령어는 액션이라 부르는 중괄호 { } 로 둘러싼 부분에서 다양한 출력이 가능합니다. "$4,$5,$1"이란 awk 명령어 내부 변수로 각각 네번째, 다섯 번재, 첫 번째 컬럼을 의미합니다.

 

awk 명령에서 공백문자는 기본 구분자이므로 로그 예에서 나오는 리퀘스트 시각[12/Apr/2021:16:47:43 +0900]는 시차를 표시하는 "+0900" 앞에 스페이스가 있어서 awk에서 다른 컬럼으로 인식해버립니다. 다라서 네 번째와 다섯 번째 컬럼을 "$4,$5"로 나란히 print 합니다.그리고 awk 명령어에서 print 할 때는 쉼표가 스페이스가 됩니다. 이때 스페이스 기호로 print할 변수를 나열하면 스페이스를 무시하기 때문에 주의해야 합니다.

$ awk '{print $4 $5 $1}' access_log
[09/Apr/2021:12:20:20+0900]xx.xx.xx.xx
[09/Apr/2021:13:21:33+0900]yy.yy.yy.yy
[09/Apr/2021:12:22:12+0900]zz.zz.zz.zz

이렇게 awk 명령어로 표시하고 싶은 컬럼 위치의 순서를 원하는 대로 바꿀 수있으므로 로그 파일을 변형할 수 있습니다.

 

에서 사용하는 $1 기호는 awk 변수와 셸 스크립트 위치 파라미터 변수 두 개가 등장합니다. 서로 완전히 다르므로 주의하기 바랍니다. awk의 print문 안에 있는 $1은 awk 내장 변수로 '첫 번째 컬럼값'을 의미합니다. 한편, 셸 스크립트의$1은 '첫 번째 명령행 인수'가 됩니다.

 

상황에 따라서는 파일명을 다른 변수에 대입해서 작성하는 것이 좋을 때도 있습니다.

logfile="$1"
awk '{print $4,$5,$1}' "$logfile" > "${logfile}.lst"

 

 

참고서적 : 유닉스 리눅스 셸 스크립트 예제 사전

반응형

댓글