세 도구는 각각 다른 일을 합니다. 역할을 먼저 나눠 두면 어떤 상황에 무엇을 꺼낼지 바로 정해집니다.
| 도구 | 역할 | 한 줄 요약 |
|---|---|---|
grep |
찾기 | 패턴이 있는 줄만 출력 |
sed |
바꾸기 | 줄 단위 치환·삭제·삽입 |
awk |
집계 | 열 단위 계산·조건·그룹 합계 |
자바에 빗대면 grep 은 filter, sed 는 map, awk 는 collect(groupingBy) 입니다. 셋 다 표준 입력을 받아 표준 출력으로 내보내므로 파이프로 이어집니다.
grep 패턴 파일 이 기본형입니다. 패턴이 포함된 줄을 전부 출력하고, 없으면 종료 코드 1 을 돌려줍니다.
| 옵션 | 뜻 | 쓰는 상황 |
|---|---|---|
-n |
줄 번호 표시 | 로그 위치 알려줄 때 |
-i |
대소문자 무시 | error/ERROR 섞였을 때 |
-c |
개수만 출력 | 에러 건수 셀 때 |
-v |
패턴 없는 줄만 | 잡음 제거 |
-r |
폴더 재귀 검색 | 설정 폴더 전체 |
-l |
파일 이름만 | 어느 파일에 있는지 |
-q |
출력 없이 코드만 | 스크립트 조건문 |
grep -q 는 스크립트에서 자주 씁니다. grep -q 'port' app.properties && echo 있음 처럼 종료 코드만 보고 분기합니다.
에러 한 줄만 보면 원인을 모릅니다. 자바 예외는 다음 줄부터 스택 트레이스가 이어지므로 뒤 몇 줄이 같이 필요합니다.
| 옵션 | 뜻 |
|---|---|
-A N |
일치 줄 뒤 N 줄 |
-B N |
일치 줄 앞 N 줄 |
-C N |
앞뒤 N 줄 |
grep -A5 'NullPointerException' app.log 가 스택 트레이스 첫 5줄을 같이 보여줍니다. 요청 파라미터가 에러 앞 줄에 찍힌다면 -B2 를 씁니다.
기본 grep 은 | 나 + 를 글자 그대로 봅니다. -E 를 붙이면 확장 정규식이 켜져 자바 Pattern 과 거의 같은 문법을 씁니다.
| 문법 | 뜻 | 예 |
|---|---|---|
a|b |
a 또는 b | ERROR|WARN |
[0-9]{3} |
숫자 3자리 | 상태 코드 |
^ $ |
줄 처음·끝 | ^java\. |
.* |
아무 글자 반복 | ERROR.*500 |
\. |
점 글자 자체 | \.log |
-o 를 더하면 줄 전체가 아니라 일치한 부분만 출력합니다. grep -oE '/api/[a-z]+' app.log | sort | uniq -c 가 경로별 호출 수를 내는 정석 조합입니다.
sed 는 스트림 편집기입니다. 기본 동작은 모든 줄을 출력하는 것이고, -n 을 주면 명시한 줄만 출력합니다.
| 명령 | 뜻 |
|---|---|
sed -n '10,20p' |
10~20 줄 |
sed -n '/ERROR/p' |
패턴 줄 |
sed -n '/09:00/,/09:05/p' |
첫 패턴부터 둘째 패턴까지 |
세 번째 구간 지정이 로그 분석에서 유용합니다. 장애 시각 앞뒤를 시각 문자열로 잘라 파일로 저장해 두면 나중에 다시 찾을 필요가 없습니다.
s/찾을것/바꿀것/ 이 치환 명령입니다. 기본은 줄마다 첫 번째 일치만 바꾸고, 끝에 g 를 붙이면 전부 바꿉니다.
구분자는 / 가 아니어도 됩니다. URL 이나 경로처럼 / 가 많은 문자열은 s#a/b#c/d# 처럼 # 를 쓰면 이스케이프가 줄어듭니다.
-E 와 괄호 그룹을 함께 쓰면 일치한 부분을 \1 \2 로 재사용합니다. sed -E 's/^([0-9-]+) ([0-9:]+) /\2 /' 는 날짜를 떼고 시각만 남깁니다.
-i 는 파일을 직접 고칩니다. 되돌릴 수 없으므로 -i.bak 처럼 접미사를 붙여 원본을 남기는 습관이 중요합니다.
sed -i.bak 's/^server.port=.*/server.port=9090/' app.properties
diff app.properties.bak app.properties # 바뀐 줄 확인^키=.* 패턴은 키로 시작하는 줄 전체를 바꿉니다. 값에 무엇이 있든 새 값으로 통째로 교체되므로 설정 치환에 가장 안전한 형태입니다.
치환 외에 세 가지 명령을 더 알면 설정 파일 작업이 끝납니다.
| 명령 | 뜻 |
|---|---|
/^#/d |
주석 줄 삭제 |
/^server.port/a\새줄 |
그 줄 뒤에 삽입 |
/password/s/=.*/=****/ |
패턴 줄에서만 치환 |
세 번째 형태는 주소와 치환을 합친 것입니다. 비밀번호 줄만 골라 값을 가리는 마스킹에 씁니다.
awk 는 줄을 공백으로 나눠 $1, $2 로 열을 부릅니다. $NF 는 마지막 열, $0 은 줄 전체입니다.
awk '{print $3}' app.log # 3번째 열
awk '$3=="ERROR"{print $2, $6}' app.log # 조건 + 열 선택
awk -F= '{print $1}' app.properties # 구분자 = 로조건{동작} 이 한 규칙입니다. 조건이 참인 줄에서만 동작이 실행되고, 조건을 생략하면 모든 줄에서 실행됩니다. -F 로 구분자를 바꾸면 CSV 나 key=value 파일도 같은 방식으로 다룹니다.
awk 는 변수를 선언 없이 쓰고, END{} 블록은 파일을 다 읽은 뒤 한 번 실행됩니다. 합계·평균·최대는 이 둘로 충분합니다.
awk '{ms=$NF+0; n++; s+=ms; if(ms>mx)mx=ms}
END{printf "n=%d avg=%.1f max=%d\n", n, s/n, mx}'$NF+0 은 45ms 같은 문자열을 숫자 45 로 바꾸는 관용구입니다. 이걸 빼면 문자열 비교가 되어 8 이 3001 보다 크다고 판단합니다. 연관 배열 c[$6]++ 를 쓰면 group by 가 되고, END 에서 for(k in c) 로 돌며 출력합니다.
파이프 중간에 끼워 쓰는 작은 도구들입니다. 각각 한 가지만 잘합니다.
| 도구 | 역할 | 예 |
|---|---|---|
cut |
열·글자 자르기 | cut -d' ' -f2 |
tr |
글자 치환 | tr 'a-z' 'A-Z' |
sort |
정렬 | sort -rn, -k2 |
uniq -c |
연속 중복 세기 | sort | uniq -c |
wc |
줄·단어·바이트 | wc -l |
xargs |
출력을 인자로 | ls | xargs grep -c E |
uniq 는 연속된 중복만 합치므로 반드시 sort 뒤에 씁니다. sort | uniq -c | sort -rn 세 단계가 "빈도 상위" 를 내는 고정 패턴입니다.
한 줄 명령은 왼쪽에서 오른쪽으로 좁혀 갑니다. 먼저 grep 으로 줄을 줄이고, awk·cut 으로 열을 고르고, sort·uniq 로 집계합니다.
grep ERROR app.log | awk '{print $6}' | sort | uniq -c | sort -rn각 단계를 하나씩 붙이며 | head 로 중간 결과를 확인하는 습관이 중요합니다. 한 번에 다 쓰고 결과가 이상하면 어느 단계가 틀렸는지 알 수 없습니다.