텍스트 인코딩과 줄바꿈
텍스트 인코딩과 줄바꿈
같은 글자라도 컴퓨터가 어떤 바이트로 저장하느냐는 시대와 환경에 따라 다릅니다. 그 결과로 한글이 깨지거나 git diff 가 의미 없는 줄 변경을 잔뜩 잡는 일이 생깁니다.
1. 인코딩의 역사
ASCII (1963) — 미국정보교환표준부호. 7비트 (0-127) 로 영문자·숫자·기본 기호. 영어권 텍스트의 토대지만 한글·일본어·중국어 표현 불가.
EUC-KR · CP949 — EUC-KR 은 한국어를 위한 8비트 인코딩. KS X 1001 한자·한글 영역을 2바이트로. 다만 EUC-KR 의 한글 영역은 KS X 1001 의 2350 자에 한정되어 일부 음절이 빠짐. CP949 (코드 페이지 949) 는 Microsoft 가 EUC-KR 을 확장해 한글 11172 자 전체를 담은 것. Windows 한국어판의 기본 ANSI 코드 페이지가 CP949.
Unicode (1991) 와 UTF-8 (1993) — Unicode 컨소시엄이 1991 년 발표한 통합 문자 집합. 모든 인류 문자에 코드 포인트 부여 (한글 '가' = U+AC00). UTF-8 은 1993 년 Ken Thompson 과 Rob Pike 가 설계한 가변 길이 인코딩:
- ASCII 영역 (0-127) 은 1바이트로, ASCII 와 완전 호환.
- 한글은 보통 3바이트.
- 이모지 같은 보조 평면 문자는 4바이트.
UTF-8 의 장점은 ASCII 호환 + 자기 동기화 (중간부터 디코딩해도 경계를 찾을 수 있음) + 엔디안 무관. 웹·Unix·대부분의 현대 도구가 UTF-8 을 기본. W3C 는 2008 년부터 HTML 에서 UTF-8 권고.
UTF-16 — 자바·.NET·Windows 내부·일부 옛 시스템이 쓰는 16비트 단위 인코딩. 한글은 2바이트, 이모지는 4바이트 (서로게이트 페어). 엔디안 (LE/BE) 이 따로.
2. BOM (Byte Order Mark)
BOM 은 파일 첫머리에 넣는 표시 바이트로, 인코딩과 엔디안을 알리는 용도.
| 인코딩 | BOM 바이트 |
|---|---|
| UTF-8 | EF BB BF |
| UTF-16 LE | FF FE |
| UTF-16 BE | FE FF |
UTF-8 은 엔디안이 없으므로 BOM 이 필수가 아니지만 일부 도구가 인코딩 식별용으로 사용:
- Microsoft Excel — CSV 를 한국어 Windows 에서 열면 ANSI (CP949) 로 추정. UTF-8 CSV 가 깨지는 사례가 흔하므로 BOM 을 붙여서 저장하면 Excel 이 UTF-8 로 인식.
- 반대로 안 좋은 경우 — 셸 스크립트 첫 줄에 BOM 이 붙으면 shebang (
#!/usr/bin/env bash) 가 깨짐. JSON 파서 일부도 BOM 에 민감.
3. 줄바꿈
| 표기 | 바이트 | 출처 |
|---|---|---|
| LF | 0A |
Unix 계열, 현대 macOS, Linux, Web |
| CR | 0D |
옛 Mac (System 9 이하). 거의 사라짐. |
| CRLF | 0D 0A |
DOS, Windows, 일부 네트워크 프로토콜 (HTTP · SMTP 헤더) |
CR (Carriage Return) 과 LF (Line Feed) 는 기계식 텔레타이프에서 각각 "캐리지를 왼쪽 끝으로", "다음 줄로 이동". DOS 가 두 동작을 모두 보내는 CRLF 를 채택했고, Unix 는 LF 하나로 단순화.
대부분의 현대 도구는 양쪽을 자동 처리. 다만 git diff · 셸 스크립트 실행 · 일부 JSON · YAML 파서 · Python 의 open(..., newline='') 같은 구체적 상황에서 차이가 드러남.
4. git 의 줄바꿈 처리
core.autocrlf:
| 값 | 동작 |
|---|---|
true |
체크아웃 시 LF→CRLF, 커밋 시 CRLF→LF (Windows 권장). |
input |
커밋 시만 CRLF→LF (macOS · Linux 권장). |
false |
변환 안 함. |
.gitattributes (권장 SSOT) — 저장소 차원에서 명시적으로 정의. core.autocrlf 보다 우선:
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
*.png binary
*.jpg binary
text=auto 는 git 이 텍스트로 판단되는 파일에 한해 정규화. eol=lf 또는 eol=crlf 는 OS 와 무관하게 강제. 바이너리는 binary 로 분명히.
5. PowerShell 5.1 의 인코딩 함정
Windows PowerShell 5.1 의 출력 cmdlet (Out-File · Set-Content · >) 기본 인코딩은 UTF-16 LE (BOM 포함). 다른 도구가 UTF-8 을 기대하는 환경에서 깨진 파일.
# 5.1 안전 패턴
"hello" | Out-File -Encoding utf8 file.txt
[System.IO.File]::WriteAllText("file.txt", "hello", [System.Text.UTF8Encoding]::new($false)) # BOM 없는 UTF-8
PowerShell 7+ 는 기본이 UTF-8 (BOM 없음) 이라 이 문제가 거의 사라짐.
6. VS Code 의 인디케이터
VS Code 우하단 상태 바는 현재 파일의 인코딩과 줄바꿈:
- 인코딩 —
UTF-8·UTF-8 with BOM·Windows 1252. - 줄바꿈 —
LF·CRLF.
클릭하면 변환·재해석 옵션. "Save with Encoding" 으로 다시 저장하거나, "Reopen with Encoding" 으로 깨진 파일을 올바른 인코딩으로 다시 읽을 수 있음.
{
"files.encoding": "utf8",
"files.eol": "\n"
}
7. 자주 쓰는 명령
| 작업 | macOS · Linux | Windows |
|---|---|---|
| 파일 인코딩 확인 | file -I path |
(PowerShell) Get-Content path -Encoding Byte -TotalCount 3 |
| LF 로 강제 변환 | dos2unix path |
dos2unix path (Git Bash) |
| CRLF 로 강제 변환 | unix2dos path |
unix2dos path |
| git 인코딩 확인 | git ls-files --eol |
동일 |
8. 자주 걸리는 자리
.sh 파일이 CRLF 로 저장되면 첫 줄 shebang 끝에 \r 이 붙어 bash\r 라는 인터프리터를 찾으려다 실패.
BOM 이 붙은 UTF-8 JSON 을 표준 라이브러리로 파싱하면 일부 언어에서 에러 (JS JSON.parse 는 BOM 을 거부하던 시절).
Excel 에서 UTF-8 CSV 한글이 깨지는 문제 — BOM 을 붙이거나 "데이터 → 텍스트 가져오기" 메뉴로 인코딩 명시.
Windows 메모장에서 저장한 텍스트가 UTF-16 LE 로 저장되어 Linux 도구가 깨지는 사례 — Windows 10 1903+ 의 메모장은 UTF-8 (BOM 없음) 기본.
Python 에서 파일을 open(path, "r") 로 열 때 기본 인코딩이 OS locale 에 의존 — Windows 한국어판은 cp949 가 기본일 수 있어 encoding="utf-8" 명시.
하고픈 말
UTF-8 + LF + .gitattributes 의 SSOT 셋이 정착되면 OS 차이로 인한 인코딩·줄바꿈 사고가 거의 사라집니다. PowerShell 5.1 의 UTF-16 LE 기본 + Excel 의 CP949 추정 두 자리만 별도로 챙기면 운영 안정.
Next
- first-terminal-day
- data-formats
The Unicode Standard · RFC 3629 UTF-8 · git-scm gitattributes · Microsoft Code Pages · Wikipedia Newline 을 참고합니다.