Journey to Security/리눅스

스트림 편집기 sed 명령/옵션 정리

Cordilog 2026. 6. 18. 18:40

1. sed란?

sed(Stream EDitor)는 입력 스트림을 줄 단위로 읽어 지정한 명령을 실행하고 결과를 출력하는 텍스트 처리 도구다.

파일을 직접 열지 않고 파이프라인에서 텍스트를 처리할 수 있어 쉘 스크립트와 시스템 자동화에서 자주 쓰인다.

1️⃣ 기본 처리 사이클

sed는 실행될 때마다 아래 순서를 반복한다.

sed는 자동 출력(auto-print) 이 기본으로 켜져 있어서 아무 명령을 지정하지 않아도 입력이 그대로 출력된다.

# 아무 명령 없이 sed만 써도 그대로 출력됨
echo -e "hello\nhi" | sed ''
hello
hi

sed ''는 빈 명령이지만 자동 출력 때문에 입력 스트림이 그대로 stdout으로 나온다.

2️⃣ -n 옵션 : 자동 출력 비활성화

-n은 이 자동 출력을 끄는 스위치다. -n을 사용하면 명시적으로 p 명령을 호출한 줄만 출력된다.

(p 명령과 세트로 보면 된다.)

# -n 없이 p → 자동출력 1번 + p 출력 1번 = 중복 2번
echo -e "hello\nhi" | sed '/hello/p'
hello   # p 명령 출력
hello   # 자동 출력
hi      # 자동 출력

# -n 있을 때 p → p가 출력한 줄만
echo -e "hello\nhi" | sed -n '/hello/p'
hello

3️⃣ -e : 다중 명령 지정 (Expression)

형식: sed -e '명령1' -e '명령2' ...

하나의 sed 실행에서 여러 명령을 순서대로 적용할 때 사용한다. -e를 쓰지 않으면 sed는 명령을 하나만 받는다고 가정하기 때문에, 두 개 이상의 명령을 쓸 때는 -e로 각각 구분해야 한다.

# -e 없이 단일 명령
sed 's/foo/bar/g' file.txt

# -e로 두 명령 순차 적용
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt

 

🔵 처리 순서: -e로 나열한 명령은 왼쪽에서 오른쪽 순서로 실행된다. 각 명령은 이전 명령의 결과를 입력으로 받는다.

# 순서가 결과에 영향을 미치는 예
echo "hello world" | sed -e 's/hello/hi/' -e 's/hi there/hey/'
# → "hi world" (두 번째 패턴 "hi there"는 매칭 안 됨)

echo "hello world" | sed -e 's/world/there/' -e 's/hello there/hey/'
# → "hey" (첫 번째 치환 후 두 번째가 매칭됨)

🔵 세미콜론 ;으로도 구분 가능: 짧은 명령은 세미콜론으로 한 줄에 이어쓸 수 있다. 결과는 -e 조합과 동일하다.

sed 's/foo/bar/g; s/baz/qux/g' file.txt

🔵 -e와 -n, -i의 조합: -e는 다른 옵션과 자유롭게 조합된다.

# -n과 조합: 패턴 매칭 줄만 출력하면서 치환도 적용
sed -n -e 's/error/ERROR/g' -e '/ERROR/p' app.log

# -i와 조합: 여러 치환을 파일에 직접 반영
sed -i.bak -e 's/localhost/db.internal/g' -e 's/3306/5432/g' app.conf

4️⃣ -i : 파일 직접 수정 (In-place edit)

형식: sed -i[백업확장자] '명령' 파일명

sed의 결과를 stdout으로 출력하는 대신 원본 파일에 직접 덮어쓴다.

기본적으로 sed는 파일을 수정하지 않고 결과를 화면에만 출력하는데, -i를 붙이면 파일 자체가 바뀐다.

# 파일 직접 수정 (백업 없음 — 위험)
sed -i 's/old/new/g' config.txt

# 백업 파일(.bak)을 남기고 수정 (권장)
sed -i.bak 's/old/new/g' config.txt
# → config.txt (수정됨), config.txt.bak (원본 보존)

🔵 백업 확장자: -i만 단독으로 쓰면 원본이 사라진다. 실수로 잘못된 패턴을 적용했을 때 복구가 불가능하므로 .bak, .orig 같은 확장자를 항상 지정하는 습관이 중요하다.

# GNU sed (Linux)
sed -i 's/foo/bar/g' file.txt

# BSD sed (macOS) — 빈 문자열 인수 필수
sed -i '' 's/foo/bar/g' file.txt

🔵 -i와 -e 조합: 여러 치환을 한 번에 파일에 반영할 때 자주 쓰인다.

sed -i.bak -e 's/localhost/db.internal/g' -e 's/3306/5432/g' app.conf

 

2. sed 주요 명령어

1️⃣ p : 출력 (Print)

형식: /찾을패턴/p

패턴에 매칭되는 줄을 출력한다. 앞서 설명한 것처럼 -n과 함께 쓰지 않으면 해당 줄이 두 번 출력된다. 실용적인 사용 패턴은 항상 -n과 조합하는 것이다.

# /etc/passwd에서 root가 포함된 줄만 출력
sed -n '/root/p' /etc/passwd

# 줄 번호와 함께 출력
sed -n '/error/p' /var/log/messages

🔵 -n과 p 조합 vs. grep : sed는 다른 명령과 함께 파이프라인에서 연속 처리가 가능하다. p로 필터링한 뒤 s로 치환하는 식의 복합 처리가 한 명령 안에서 이루어진다.


2️⃣ s : 교체 (Substitute)

형식: s/찾을패턴/바꿀문자열/[옵션]

sed에서 가장 많이 쓰이는 명령이다. 기본적으로 각 줄에서 첫 번째 매칭만 교체한다.

# 첫 번째 "foo"만 "bar"로 교체
echo "foo foo foo" | sed 's/foo/bar/'
bar foo foo

# g 옵션: 줄 내 모든 매칭 교체
echo "foo foo foo" | sed 's/foo/bar/g'
bar bar bar

🔵 g 옵션 (global): 줄 안에서 패턴이 여러 번 나타날 때 전부 교체하려면 g를 붙인다. g 없이는 첫 번째 매칭에서 멈춘다.

🔵 구분자 변경: 경로처럼 /가 포함된 문자열을 교체할 때는 구분자를 바꿀 수 있다.

# /을 포함한 경로 치환 시 구분자를 |나 #으로 변경
sed 's|/usr/local|/opt|g' config.txt
sed 's#http://old.example.com#https://new.example.com#g' urls.txt

 

3️⃣ i : 앞에 삽입 (Insert before)

형식: /찾을패턴/i삽입문자열

패턴에 매칭된 줄 **위(앞)**에 새 줄을 삽입한다.

# "server {" 줄 위에 주석 삽입
sed '/server {/i# Auto-generated block' nginx.conf

# 결과:
# Auto-generated block
# server {
#     listen 80;

 

4️⃣ a : 뒤에 추가 (Append after)

형식: /찾을패턴/a삽입문자열

패턴에 매칭된 줄 **아래(뒤)**에 새 줄을 추가한다. i와 방향이 반대다.

# "[section]" 줄 바로 아래에 항목 추가
sed '/\[section\]/akey=value' config.ini

# 결과:
# [section]
# key=value

🔵 i와 a 비교

명령 삽입 위치
i 매칭 줄 insert = 앞에 끼워 넣기
a 매칭 줄 아래 append = 뒤에 붙이기

 

5️⃣ y : 문자 변환 (Transliterate)

형식: [범위]y/원본문자셋/변환문자셋/

tr 명령과 유사하게 문자를 1:1로 대응시켜 변환한다. s는 문자열 패턴을 교체하지만, y는 개별 문자 단위로 변환한다.

# 소문자 a-z를 대문자 A-Z로 변환
echo "hello world" | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'
HELLO WORLD

# 1~3번 줄에서만 변환 (범위 지정)
sed '1,3y/abc/ABC/' file.txt

🔵 s와 y의 차이: s는 정규표현식 패턴을 쓸 수 있고 문자열 단위로 교체한다. y는 정규표현식을 지원하지 않으며 원본과 변환 문자셋의 길이가 반드시 같아야 한다.


6️⃣ r : 파일 읽기 (Read file)

형식: /찾을패턴/r 파일명

패턴에 매칭된 줄 다음에 지정한 파일의 내용을 삽입한다. 템플릿에 외부 파일을 끼워 넣는 용도로 활용된다.

# "INSERT_HERE" 줄 뒤에 footer.txt 내용 삽입
sed '/INSERT_HERE/r footer.txt' template.html

# 파이프와 함께 - /etc/hosts의 특정 섹션 뒤에 추가 설정 삽입
sed '/# Custom hosts/r /tmp/extra_hosts' /etc/hosts

7️⃣ d : 줄 삭제 (Delete)

형식: /찾을패턴/d

패턴에 매칭되는 줄을 삭제한다.

정확히는 해당 줄을 패턴 스페이스에서 지우고 자동 출력을 건너뛴 뒤 다음 줄로 넘어간다.

# 주석 줄(#으로 시작) 삭제
sed '/^#/d' config.txt

# 빈 줄 삭제
sed '/^$/d' config.txt

# 주석 줄과 빈 줄 동시 삭제 (-e 조합)
sed -e '/^#/d' -e '/^$/d' config.txt

🔵 d vs -n/p 조합: -n과 p로 원하는 줄만 출력하는 방식과 d로 불필요한 줄을 제거하는 방식은 결과적으로 같은 필터링이지만 동작은 반대로 한다. 남길 줄이 적으면 -n/p, 제거할 줄이 적으면 d가 더 직관적이다.

🔵 범위 지정과 조합: 줄 번호나 범위를 지정해서 특정 구간을 통째로 삭제할 수 있다.

# 1~5번 줄 삭제
sed '1,5d' file.txt

# 마지막 줄 삭제
sed '$d' file.txt

# "START"부터 "END"까지의 줄 삭제
sed '/START/,/END/d' file.txt

3. 자주 조합하는 패턴

sed는 단일 명령에서 쓰기보다 주로 여러 명령을 -e로 연결하거나 세미콜론으로 조합해서 쓴다.

# 복수 명령 조합: 주석 줄 삭제 + 빈 줄 삭제 + foo→bar 치환
sed -e '/^#/d' -e '/^$/d' -e 's/foo/bar/g' config.txt

# -n과 p 조합으로 특정 범위 줄만 추출 (10~20번 줄)
sed -n '10,20p' largefile.log

# 파일 직접 수정 (-i 옵션, 백업 권장)
sed -i.bak 's/old_password/new_password/g' app.conf