리눅스 sed 명령어 사용법 - 문자열 치환 옵션 정리와 실전 예제
이 명령어를 언제 쓰는가
서버 30대의 설정 파일에서 같은 값을 바꿔야 할 때, 배포 스크립트가 템플릿의 자리표시자를 실제 값으로 갈아끼워야 할 때, 500MB 짜리 로그에서 특정 줄 범위만 잘라내야 할 때 sed를 쓴다. 편집기를 열지 않고 규칙으로 파일을 고치는 도구다.
sed 의 값어치는 사람 손을 빼는 데 있다. vi 로 서버마다 열어 고치면 30번 중 한 번은 실수가 나지만, sed 한 줄은 30대에서 정확히 같게 동작한다. 대신 -i 는 원본을 즉시 덮어쓰므로, 먼저 화면으로 확인하고 그다음에 적용하는 순서를 몸에 붙여야 한다.
기본 형식
sed [옵션] '주소범위 명령' 파일
- 주소범위 — 생략하면 모든 줄.
3(3번 줄),10,20(범위),/패턴/(패턴이 있는 줄),$(마지막 줄)로 쓴다. - 명령 —
s(치환),d(삭제),p(출력),a(뒤에 추가),i(앞에 삽입),c(줄 통째 교체). - 가장 많이 쓰는 형태는 치환이다.
s/찾을것/바꿀것/g에서g는 한 줄에 여러 번 나와도 전부라는 뜻이다.
자주 쓰는 옵션
| 옵션 | 의미 | 예시 |
|---|---|---|
| (없음) | 결과를 화면에만 출력. 원본은 그대로 | sed 's/dev/prod/g' app.conf |
-i | 파일을 직접 수정한다 | sed -i 's/dev/prod/g' app.conf |
-i.bak | 수정하되 원본을 파일.bak 으로 남긴다 | sed -i.bak 's/dev/prod/g' app.conf |
-n | 자동 출력을 끈다. p 와 짝으로 쓴다 | sed -n '100,120p' app.log |
-E | 확장 정규식 사용(+, ?, () 를 그대로) | sed -E 's/[0-9]+/N/g' a.txt |
-e | 여러 명령을 이어 붙인다 | sed -e 's/a/b/' -e '/^#/d' a.txt |
-f 파일 | 스크립트를 파일에서 읽는다 | sed -f rules.sed a.txt |
-s | 여러 파일을 각각 별개로 취급 | sed -s -n '1p' *.log |
실전 예제
1. 설정값을 확인하고 나서 바꾼다. 실무에서 sed 를 쓰는 정석 순서다. 첫 줄로 결과를 눈으로 보고, 같은 명령에 -i.bak 만 붙여 적용한다.
sed -E 's/^(max_connections)[[:space:]]*=.*/\1 = 500/' /etc/my.cnf.d/server.cnf | grep max_connections
sudo sed -i.bak -E 's/^(max_connections)[[:space:]]*=.*/\1 = 500/' /etc/my.cnf.d/server.cnf
^ 로 줄 시작을 고정한 이유는 주석 처리된 #max_connections 까지 건드리지 않기 위해서다. 이 앵커가 없으면 주석까지 바뀐다.
2. 거대한 로그에서 특정 구간만 잘라낸다. 몇 GB 짜리 로그를 통째로 열 수 없을 때 쓴다. q 를 붙이면 그 지점에서 읽기를 멈춰 파일 끝까지 훑지 않는다.
sed -n '10000,10200p; 10201q' /var/log/app/application.log
장애 시각으로 자르려면 패턴 범위를 쓴다.
sed -n '/2026-08-25 03:1/,/2026-08-25 03:2/p' /var/log/app/application.log
3. 주석과 빈 줄을 걷어내고 실제 설정만 본다. 수백 줄짜리 설정 파일의 실제 내용을 파악하는 가장 빠른 방법이다.
sed -e 's/#.*//' -e '/^[[:space:]]*$/d' /etc/nginx/nginx.conf
4. 배포 시 템플릿의 자리표시자를 채운다. 경로에 / 가 들어가므로 구분자를 | 로 바꾼 것이 요점이다.
sed -e "s|__APP_HOME__|/opt/app|g" \
-e "s|__VERSION__|1.4.0|g" \
app.service.tmpl > /etc/systemd/system/app.service
5. 특정 줄 뒤에 설정을 끼워 넣는다. 파일 끝에 붙이면 안 되고 특정 블록 안에 들어가야 할 때 쓴다.
sudo sed -i '/^\[mysqld\]$/a character-set-server = utf8mb4' /etc/my.cnf.d/server.cnf
6. 여러 서버에 같은 수정을 적용한다. sed 의 본래 값어치가 나오는 지점이다.
for h in web01 web02 web03; do
ssh "$h" 'sudo sed -i.bak "s/^worker_processes .*/worker_processes auto;/" /etc/nginx/nginx.conf && sudo nginx -t'
done
함정과 주의점
GNU sed 와 macOS(BSD) sed 의 -i 는 문법이 다르다. 리눅스에서 되던 명령이 맥에서 이상한 파일을 만든다.
sed -i 's/a/b/' f.txt # 리눅스: 정상. macOS: -i 의 인자로 's/a/b/' 를 백업 확장자로 먹는다
sed -i '' 's/a/b/' f.txt # macOS 에서 백업 없이 수정
sed -i.bak 's/a/b/' f.txt # 양쪽 모두 동작한다
맥과 리눅스를 오가며 쓰는 스크립트라면 항상 -i.bak 형태로 쓰는 것이 안전하다.
-i 는 확인 절차가 없다. 정규식을 한 글자 잘못 써도 그대로 저장되고, 되돌릴 방법이 없다. 운영 설정 파일에는 반드시 -i.bak 을 붙이고, 붙이지 않을 거라면 먼저 -i 없이 실행해 화면으로 결과를 본다.
치환 대상에 / 가 들어가면 구분자를 바꾼다. s/\/var\/log/\/data\/log/ 처럼 이스케이프를 늘리면 읽기 어려워지고 실수가 늘어난다. sed 는 구분자를 자유롭게 고를 수 있으므로 s|/var/log|/data/log| 로 쓴다.
바꿀 문자열의 & 는 특수문자다. 치환 결과에서 & 는 찾은 문자열 전체로 치환된다. 문자 그대로 넣으려면 \& 로 이스케이프한다. URL 이나 쿼리 문자열을 다룰 때 자주 걸린다.
심볼릭 링크를 -i 로 수정하면 링크가 일반 파일로 바뀐다. GNU sed 는 링크 자체를 새 파일로 대체하기 때문이다. 링크가 가리키는 원본을 고치려면 --follow-symlinks 를 붙인다. /etc/nginx/sites-enabled/ 처럼 링크로 구성된 디렉터리에서 실제로 문제가 된다.
함께 보면 좋은 명령어
awk— 열 단위 처리, 조건 계산, 집계는 sed 로 억지로 하지 말고 awk 로 넘긴다.grep— 고칠 대상이 실제로 몇 줄인지 먼저 세어본다.grep -c로 확인하고 sed 를 친다.diff—-i.bak으로 남긴 백업과 비교해 무엇이 바뀌었는지 확인한다.