동작하는 코드
예제 1: grep과 wc로 기본 텍스트 분석
파이프를 활용해 단계별로 데이터를 처리합니다:
# notes.md에서 항목 수 세기
grep "항목" Documents/notes.md | wc -l
출력:
2
# 특정 패턴을 포함하는 줄 찾기
cat Documents/notes.md | grep "^-"
출력:
- 항목 1
- 항목 2
예제 2: head와 tail 조합
# 파일의 앞부분과 뒷부분 동시에 확인
head -2 Documents/notes.md
echo "---"
tail -1 Documents/notes.md
출력:
# 메모
- 항목 1
---
- 항목 2
예제 3: 검색 결과를 파일로 저장
# grep 결과를 파일에 저장
grep "항목" Documents/notes.md > found.txt
cat found.txt
출력:
- 항목 1
- 항목 2
# wc로 여러 파일 통계 비교
wc -l Documents/hello.txt Documents/notes.md
출력:
1 Documents/hello.txt
3 Documents/notes.md
4 total
직접 수정하기
awk: 열 기반 텍스트 처리
awk는 텍스트 처리에 특화된 미니 언어입니다. 특히 CSV처럼 구분자로 나뉜 데이터 처리에 강력합니다.
기본 구조:
awk '패턴 { 액션 }' 파일
예제: 기본 열 출력
# 준비: 간단한 CSV 만들기
echo "이름,점수,등급" > scores.csv
echo "홍길동,85,B" >> scores.csv
echo "김철수,92,A" >> scores.csv
echo "이영희,78,C" >> scores.csv
echo "박민수,65,D" >> scores.csv
# 첫 번째 열만 출력 (-F','는 구분자를 쉼표로 지정)
awk -F',' '{ print $1 }' scores.csv
출력:
이름
홍길동
김철수
이영희
박민수
# 이름과 점수만 출력
awk -F',' '{ print $1, $2 }' scores.csv
출력:
이름 점수
홍길동 85
김철수 92
이영희 78
박민수 65
조건 필터링
# 2열(점수)이 80 이상인 행만 출력
awk -F',' '$2 >= 80' scores.csv
출력:
이름,점수,등급
홍길동,85,B
김철수,92,A
# 헤더 제외하고 80 이상만 (NR: 줄 번호)
awk -F',' 'NR > 1 && $2 >= 80' scores.csv
출력:
홍길동,85,B
김철수,92,A
집계: BEGIN과 END
# 평균 계산
awk -F',' 'NR > 1 { sum += $2; count++ } END { print "평균:", sum/count }' scores.csv
출력:
평균: 80
# 파이프로 연결
cat scores.csv | awk -F',' 'NR > 1 { print $1, $2 }'
출력:
홍길동 85
김철수 92
이영희 78
박민수 65
"왜?" — 텍스트 처리 도구가 필요한 이유
서버 로그, CSV 데이터, 설정 파일 등 대부분의 데이터는 텍스트입니다. 이 도구들을 파이프로 조합하면 스프레드시트나 전용 프로그램 없이도 데이터를 빠르게 분석할 수 있습니다.
실전 시나리오: 로그 분석
접속 로그가 있다고 가정합니다:
2024-01-15 10:30:01 INFO 사용자 로그인: user001
2024-01-15 10:30:05 ERROR 데이터베이스 연결 실패
2024-01-15 10:30:10 INFO 파일 업로드 완료
2024-01-15 10:31:00 WARN 메모리 사용량 80% 초과
2024-01-15 10:31:05 ERROR 파일 저장 실패
# ERROR 로그만 필터
grep "ERROR" app.log
# ERROR 개수 세기
grep -c "ERROR" app.log
# 특정 시간대 로그 추출
grep "10:30" app.log | grep "ERROR"
# ERROR 메시지만 파일로 저장
grep "ERROR" app.log > errors.txt
awk 핵심 개념 정리
| 개념 | 설명 | 예시 |
| ------------- | ------------ | ------------------------ |
| $0 | 전체 줄 | print $0 |
| $1, $2... | 각 열 | print $1, $3 |
| NR | 줄 번호 | NR > 1 (헤더 제외) |
| NF | 필드(열) 수 | print NF |
| -F | 구분자 지정 | -F',', -F'\t' |
| BEGIN | 처리 전 실행 | BEGIN { print "시작" } |
| END | 처리 후 실행 | END { print sum } |
흔한 실수
실수 1: awk 열 번호는 1부터 시작
# 잘못됨: $0이 첫 번째 열이 아님
awk -F',' '{ print $0 }' file.csv # 전체 줄 출력
# 올바름
awk -F',' '{ print $1 }' file.csv # 첫 번째 열
실수 2: 구분자 지정 빠뜨리기
# 구분자가 쉼표인 CSV를 공백으로 처리 (틀림)
awk '{ print $1 }' scores.csv
# "이름,점수,등급"을 통째로 $1로 처리
# 올바름
awk -F',' '{ print $1 }' scores.csv
실수 3: 파이프 결과를 항상 확인하기
# 각 단계를 확인하며 파이프 구성
cat scores.csv | head -3 # 1단계 확인
cat scores.csv | head -3 | grep "8" # 2단계 확인
복잡한 파이프를 한번에 작성하기보다 단계별로 결과를 확인하며 만드세요.
심화 학습
awk 심화: 패턴 매칭과 필드 연산
# 특정 패턴의 행만 처리
awk -F',' '/A/ { print $1, "우수" }' scores.csv
# 필드 연산
awk -F',' 'NR > 1 { print $1, $2 * 1.1, "보정후" }' scores.csv
# 여러 조건
awk -F',' 'NR > 1 && $2 >= 80 && $3 == "A"' scores.csv
# 출력 형식 지정
awk -F',' 'NR > 1 { printf "%-10s %3d점\n", $1, $2 }' scores.csv
sed: 스트림 편집기
sed는 텍스트를 변환하는 도구입니다:
# 텍스트 치환 (s/원본/교체/)
echo "Hello World" | sed 's/World/Terminal/'
# 전역 치환 (g 플래그)
echo "aaa bbb aaa" | sed 's/aaa/xxx/g'
# 특정 줄 삭제
cat file.txt | sed '2d'
# 줄 번호 추가
cat file.txt | sed '='
sed는 파일 자체를 수정하지 않고 stdout으로 결과를 냅니다. 파일을 수정하려면 -i 옵션을 씁니다.
파이프 연결 시 오류 처리
파이프 중간에 명령어가 실패하면 결과가 이상해질 수 있습니다:
# set -o pipefail: 파이프 중 하나라도 실패하면 전체 실패로 처리
set -o pipefail
# 각 단계를 변수에 저장해 디버깅
result=$(cat file.txt | grep "pattern")
echo "결과: $result"
echo "a,1" > data.csv,echo "b,2" >> data.csv,echo "c,3" >> data.csv로 파일을 만드세요.awk -F',' '{ print $1 }' data.csv로 첫 번째 열을 출력하세요.awk -F',' '$2 >= 2' data.csv로 두 번째 열이 2 이상인 행을 필터링하세요.awk -F',' '{ sum += $2 } END { print sum }' data.csv로 두 번째 열의 합계를 구하세요.cat Documents/notes.md | grep "항목" | wc -l로 항목 수를 세세요.
Q1. awk -F',' '$2 >= 80' scores.csv에서 -F','의 역할은?
- A) 80보다 큰 값을 필터링하는 조건
- B) 열 구분자를 쉼표로 지정
- C) 파일 형식을 CSV로 지정
- D) 두 번째 파일을 지정