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"
참고서적 : 유닉스 리눅스 셸 스크립트 예제 사전
'IT 이야기 > Linux 셸 스크립트' 카테고리의 다른 글
[Linux 셸 스크립트] 텍스트 처리 - 078 시스템 로그에서 IP 주소마다 횟수 집계하기 (0) | 2021.04.12 |
---|---|
[Linux 셸 스크립트] 텍스트 처리 - 077 웹 서버 로그 파일에서 특정 상태값만 취득하기 (0) | 2021.04.12 |
[Linux 셸 스크립트] 텍스트 처리 - 075 숫자값(CSV 파일)에서 "*"를 써서 간단한 텍스트 그래프 출력하기 (0) | 2021.04.09 |
[Linux 셸 스크립트] 텍스트 처리 - 074 숫자로 된 CSV 파일에서 평균값 계산하기 (0) | 2021.04.09 |
[Linux 셸 스크립트] 텍스트 처리 - 073 CSV 파일에 ID 목록을 입력해서 대응하는 ID 컬럼값 얻기 (0) | 2021.04.08 |
댓글