# sed 빠른 참조

*스트림 편집, 치환, 주소, 홀드 공간, 인플레이스 변환*

> Source: GNU sed Manual (gnu.org/software/sed) · MIT

## 기본

### sed 실행

```
sed 's/old/new/' file.txt          # 줄당 첫 번째 일치 치환
sed 's/old/new/g' file.txt         # 줄당 모든 일치 치환
sed -n '5p' file.txt               # 5번째 줄만 출력
sed '3d' file.txt                  # 3번째 줄 삭제
echo "hello" | sed 's/hello/hi/'   # 파이프 입력
```

### 커맨드라인 플래그

| Command | Description |
|---------|-------------|
| `-n` | 자동 출력 억제; `p`로만 출력 |
| `-e 'cmd'` | sed 명령 실행 (여러 개는 `-e`로 연결) |
| `-f script.sed` | 파일에서 명령 읽기 |
| `-i[suffix]` | 파일을 인플레이스 편집 (선택적 백업 접미사) |
| `-E / -r` | 확장 정규 표현식 사용 |

## 치환

### 치환 문법

```
sed 's/foo/bar/' f                 # 줄당 첫 번째 발생
sed 's/foo/bar/g' f                # 모든 발생
sed 's/foo/bar/3' f                # 세 번째 발생만
sed 's/foo/bar/gi' f               # 모두, 대소문자 무시
sed 's|/usr/bin|/opt/bin|g' f      # 대체 구분자
```

### 치환 플래그

| Command | Description |
|---------|-------------|
| `g` | 줄의 모든 발생 교체 |
| `N (숫자)` | N번째 발생만 교체 |
| `p` | 치환된 경우 줄 출력 |
| `w file` | 치환된 줄을 파일에 쓰기 |
| `i / I` | 대소문자 무시 일치 (GNU) |

## 주소

### 주소 예시

```
sed '3s/a/b/' f                    # 3번째 줄만
sed '2,5s/a/b/' f                  # 2번째부터 5번째 줄
sed '/^#/d' f                      # #으로 시작하는 줄 삭제
sed '/start/,/end/d' f             # 패턴 사이 범위 삭제
sed '1~2d' f                       # 홀수 번호 줄 삭제 (GNU)
```

### 주소 유형

| Command | Description |
|---------|-------------|
| `N` | 줄 번호 N |
| `$` | 마지막 줄 |
| `N,M` | N부터 M까지의 줄 범위 |
| `/regex/` | 정규식과 일치하는 줄 |
| `/regex1/,/regex2/` | 첫 번째 일치부터 두 번째 일치까지 범위 |
| `N~step` | N부터 시작하여 step마다 (GNU) |
| `addr!` | 부정 — 일치하지 않는 줄에 적용 |

## 삭제 및 출력

### 삭제 및 출력 명령어

```
sed '5d' f                         # 5번째 줄 삭제
sed '/^$/d' f                      # 빈 줄 삭제
sed -n '10,20p' f                  # 10~20번째 줄 출력
sed -n '/error/p' f                # 패턴과 일치하는 줄 출력
sed '/debug/!d' f                  # 일치하는 줄만 유지
```

### 명령어 참조

| Command | Description |
|---------|-------------|
| `d` | 패턴 공간 삭제, 다음 사이클 시작 |
| `D` | 패턴 공간에서 첫 번째 개행까지 삭제 |
| `p` | 패턴 공간 출력 |
| `P` | 패턴 공간에서 첫 번째 개행까지 출력 |
| `q` | 현재 패턴 공간 출력 후 종료 |
| `Q` | 출력 없이 종료 (GNU) |

## 삽입 및 추가

### 삽입, 추가, 변경

```
sed '3i\inserted line' f           # 3번째 줄 앞에 삽입
sed '3a\appended line' f           # 3번째 줄 뒤에 추가
sed '3c\replaced line' f           # 3번째 줄 교체
sed '/marker/a\new line' f         # 패턴 일치 후 추가
```

### 명령어

| Command | Description |
|---------|-------------|
| `i\text` | 현재 줄 앞에 텍스트 삽입 |
| `a\text` | 현재 줄 뒤에 텍스트 추가 |
| `c\text` | 현재 줄을 텍스트로 교체 |
| `r file` | 파일 내용 읽어 추가 |
| `R file` | 파일에서 한 줄 읽어 추가 (GNU) |
| `w file` | 패턴 공간을 파일에 쓰기 |

## 홀드 공간

### 홀드 공간 명령어

| Command | Description |
|---------|-------------|
| `h` | 패턴 공간을 홀드 공간에 복사 |
| `H` | 패턴 공간을 홀드 공간에 추가 |
| `g` | 홀드 공간을 패턴 공간에 복사 |
| `G` | 홀드 공간을 패턴 공간에 추가 |
| `x` | 패턴 공간과 홀드 공간 교환 |

### 홀드 공간 예시

```
sed -n '1!G;h;$p' f               # 줄 역순 (tac)
sed '/^$/{ x; s/\n//; x; }' f     # 빈 줄에서 홀드 축소
sed -n 'H;${x;s/\n/ /g;p;}' f     # 모든 줄을 공백으로 합치기
```

## 다중 명령어

### 명령어 연결

```
sed -e 's/foo/bar/g' -e 's/baz/qux/g' f
sed 's/foo/bar/g; s/baz/qux/g' f
sed '/header/{ s/old/new/; s/foo/bar/; }' f
sed -f commands.sed input.txt
```

### 그룹화 및 분기

| Command | Description |
|---------|-------------|
| `{ cmd1; cmd2; }` | 같은 주소에 명령어 그룹화 |
| `:label` | 분기 레이블 정의 |
| `b label` | 레이블로 분기(점프) |
| `t label` | 마지막 `s///`가 성공하면 분기 |
| `T label` | 마지막 `s///`가 실패하면 분기 (GNU) |

## 인플레이스 편집

### 인플레이스 예시

```
sed -i 's/old/new/g' file.txt            # 인플레이스 편집 (GNU)
sed -i.bak 's/old/new/g' file.txt        # file.txt.bak으로 백업
sed -i '' 's/old/new/g' file.txt         # macOS 인플레이스 (백업 없음)
sed -i '/^#/d' config.txt                # 인플레이스로 주석 제거
```

### 플랫폼 참고

| Command | Description |
|---------|-------------|
| `GNU sed -i` | 접미사 선택사항; `-i`만으로 백업 없이 편집 |
| `BSD/macOS sed -i` | 접미사 필수; 백업 없으면 `-i ''` 사용 |
| `-i.bak` | `.bak` 확장자로 백업 파일 생성 |
| `Multiple files` | `sed -i 's/a/b/g' *.txt`로 모든 일치 파일 편집 |

## 정규식

### sed의 정규식

| Command | Description |
|---------|-------------|
| `.` | 임의의 단일 문자 |
| `*` | 앞 항목의 0회 이상 반복 |
| `\+` | 1회 이상 (BRE) — ERE에서는 `+` |
| `\?` | 0회 또는 1회 (BRE) — ERE에서는 `?` |
| `^` | 줄의 시작 |
| `$` | 줄의 끝 |
| `[abc]` | 문자 클래스 |
| `\( \)` | 캡처 그룹 (BRE) — ERE에서는 `()` |
| `\1, \2` | 캡처 그룹 역참조 |
| `&` | 전체 일치 문자열 (교체에서) |

### 정규식 예시

```
sed 's/[0-9]\+/NUM/g' f               # 숫자 교체
sed -E 's/(foo)(bar)/\2\1/g' f         # 그룹 교환 (ERE)
sed 's/.*/(&)/' f                      # 줄을 괄호로 감싸기
sed 's/[ \t]*$//' f                    # 후행 공백 제거
```

## 일반 패턴

### 원라이너

```
sed -n '1p' f                          # 첫 번째 줄 (head -1)
sed '$!d' f                            # 마지막 줄 (tail -1)
sed '/^$/d' f                          # 빈 줄 제거
sed 's/^[ \t]*//' f                    # 앞 공백 제거
sed '=' f | sed 'N;s/\n/\t/' f         # 줄 번호 매기기
```

### 레시피

| Command | Description |
|---------|-------------|
| `이중 간격` | `sed G` — 각 줄 뒤에 빈 줄 추가 |
| `HTML 태그 제거` | `sed 's/<[^>]*>//g'` |
| `이메일 추출` | `sed -nE 's/.*([a-z]+@[a-z.]+).*/\1/p'` |
| `줄 주석 처리` | `sed 's/^/# /'` — 각 줄 앞에 `# ` 추가 |
| `EOF의 빈 줄 제거` | `sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'` |
| `N번째 줄 교체` | `sed 'Nc\new text'` — N번째 줄 교체 |
