티스토리 뷰

레거시 시스템에서 넘어온 CSV 수백 개를 열었더니 한글이 전부 깨져 있었다. euc-kr(정확히는 cp949)로 저장된 파일을 utf-8 환경에서 열었을 때 나오는 전형적인 증상이다.

파일이 한두 개면 에디터로 열어서 다시 저장하면 되지만, 수백 개는 그렇게 못 한다. iconv와 셸 스크립트로 한 번에 처리한다.

기본 스크립트

#!/bin/bash

# csv 파일 목록을 가져온다
csv_files=`ls -1 *.csv`

# 변환 결과를 담을 디렉터리
mkdir -p utf8

for csv_file in $csv_files; do
  iconv -c -f euc-kr -t utf-8 "$csv_file" > "utf8/$csv_file"
done

옵션 의미는 이렇다.

  • -f euc-kr : 원본 인코딩
  • -t utf-8 : 변환할 인코딩
  • -c : 변환할 수 없는 문자를 버리고 계속 진행

-c 옵션은 양날의 검이다

-c가 없으면 변환 불가 문자를 만나는 순간 에러로 중단된다. 그래서 대량 처리에는 편한데, 문제가 있는 문자를 조용히 삭제한다는 게 함정이다.

데이터가 중요하다면 -c 없이 먼저 돌려서 어느 파일이 실패하는지 확인하는 편이 낫다.

for f in *.csv; do
  if ! iconv -f euc-kr -t utf-8 "$f" > /dev/null 2>&1; then
    echo "변환 실패: $f"
  fi
done

실패 목록을 먼저 뽑고, 그 파일들만 따로 살펴본 뒤에 전체를 돌리는 순서를 권한다.

euc-kr 대신 cp949를 쓰는 게 안전하다

한국어 파일에서 자주 겪는 함정이다. 윈도우에서 만들어진 한글 파일은 대부분 cp949(= MS949, euc-kr 확장)다. euc-kr은 완성형 2,350자만 담고 있어서, 그 밖의 확장 문자가 들어 있으면 변환에 실패한다.

# euc-kr 로 실패하면 cp949 로 시도
iconv -f cp949 -t utf-8 input.csv > output.csv

실무에서는 그냥 처음부터 cp949로 지정하는 게 실패가 적다. cp949는 euc-kr의 상위 호환이라 euc-kr 파일도 문제없이 읽는다.

원본 인코딩을 모를 때

파일마다 인코딩이 섞여 있을 수도 있다. file 명령으로 추정할 수 있다.

file -I *.csv
# 또는 (리눅스)
file -bi *.csv

# 더 정확하게는 uchardet
brew install uchardet   # macOS
uchardet input.csv

인코딩별로 분기 처리하는 스크립트도 만들 수 있다.

for f in *.csv; do
  enc=$(uchardet "$f")
  if [ "$enc" = "UTF-8" ]; then
    echo "이미 UTF-8: $f"
    cp "$f" "utf8/$f"
  else
    iconv -f "$enc" -t utf-8 "$f" > "utf8/$f"
  fi
done

하위 디렉터리까지 한 번에

ls *.csv는 현재 디렉터리만 본다. 하위까지 훑으려면 find를 쓴다.

find . -name "*.csv" -type f | while read -r f; do
  out="utf8/${f#./}"
  mkdir -p "$(dirname "$out")"
  iconv -c -f cp949 -t utf-8 "$f" > "$out"
done

파일명에 공백이 있을 수 있으니 while read -r과 큰따옴표를 반드시 쓴다. for f in $(find ...) 형태는 공백에서 깨진다.

엑셀에서 열 거라면 BOM을 붙인다

utf-8로 잘 변환했는데 엑셀에서 열면 또 깨지는 경우가 있다. 엑셀은 BOM이 없는 utf-8 CSV를 시스템 기본 인코딩으로 해석하기 때문이다.

# BOM 추가
for f in utf8/*.csv; do
  printf '\xEF\xBB\xBF' | cat - "$f" > tmp && mv tmp "$f"
done

반대로 프로그램에서 파싱할 거라면 BOM이 오히려 방해가 된다. 첫 컬럼명 앞에 보이지 않는 문자가 붙어서 헤더 매칭이 실패한다. 용도에 따라 붙이거나 떼면 된다.

파일명 자체가 깨진 경우

내용이 아니라 파일명이 깨졌다면 convmv를 쓴다.

brew install convmv   # macOS

# 미리보기 (실제 변경 안 함)
convmv -f cp949 -t utf-8 *.csv

# 실제 적용
convmv -f cp949 -t utf-8 --notest *.csv

맥에서는 한 가지 더 주의할 게 있다. macOS는 파일명을 NFD(자모 분리) 형태로 저장한다. "한글.csv"가 리눅스에서는 "ㅎㅏㄴㄱㅡㄹ.csv"처럼 보일 수 있다. 이 경우 -t utf-8 대신 --nfc 옵션이 필요하다.

정리

  • iconv -f cp949 -t utf-8 이 euc-kr보다 실패가 적다
  • -c는 변환 불가 문자를 조용히 버린다. 중요 데이터면 먼저 검증
  • 인코딩을 모르면 file -I 또는 uchardet
  • 하위 디렉터리는 find + while read -r, 공백 주의
  • 엑셀에서 열 거면 BOM 추가, 프로그램 파싱이면 BOM 제거
  • 파일명이 깨졌으면 convmv
댓글


최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday