macOS에서 한글 파일/디렉터리 잘 다루기

어쩌다보니 macOS / linux / MS Windows를 모두 사용하고 있는데, macOS만 유니코드(특히 한글) 파일/디렉터리 이름을 다루는 방식이 달라서 괴롭다. 현대 OS는 다들 유니코드를 사용한다. 그런데 개별 OS에서 주로 사용하는 표현 방식이 다르기도 한데, 이 중 macOS가 특히 다른 것.

배경을 좀 더 설명하자면, 유니코드로 동일한 의미의 글자를 표현할 방법이 네 가지가 있고 이를 normalization form 이라고 부른다.

  • NFD: 정준 분해 형식. 예를 들어 “한글"이라는 단어는 “ㅎㅏㄴㄱㅡㄹ” 처럼 저장한다. 총 6개의 코드 포인트란 의미. (풀어쓰면 U+1112 U+1161 U+11AB U+1100 U+1173 U+11AF) 각각 초성/중성/종성이 별개의 코드 포인트고, 이는 NFC에서의 코드 포인트와 다르다.)
  • NFC: 정준 분해 후 조합. 예를 들어 “한글"이라는 단어는 “한"과 “글"에 해당하는 두 개의 코드 포인트로 표현한다. (U+D55C U+AE00 두 코드 포인트에 해당)

추가로 NFKD, NFKC가 있는데 한글 표현 형식에 있어서는 NFD/NFC와 각각 동일한 형이 나온다. (다만 한글 자모 표현에서 어떤지는 내 지식이 얕아서 모르겠으니 이 부분까지 필요하다면 직접 확인하시라)

macOS가 괴로운 것은 OS 수준에서 — 예를 들어 finder — 파일을 생성하거나 하면 NFD로 처리하기 때문. 다들 이렇게 처리하면 상관없겠지만, 거의 항상 NFC로 처리하는 MS Windows나 사실상 NFC로 처리하는게 대세인 linux와 파일을 주고 받기가 매우 괴롭다. 그래서 일부 도구에선 이걸 좀 편하게 처리하게 해준다. 예를 들어서,

  • gmail 로 파일을 보낸다면, 알아서 파일이름 부분을 재정규화한다. 즉, NFD로 한글 이름 파일을 보내도 NFC로 바꾼다.
  • iTerm2 같은 터미널 에뮬레이터에서는 유니코드 정규화 방식을 선택할 수 있다. (나는 이걸 NFC로 해놓고 쓴다)

나는 아직도 linux/macOS에선 파일을 주로 터미널로 다룬다. 특히 검색 / 편집 / 백업 등을 할 때는 터미널을 더 선호한다. 그렇다보니 find . type -f -name '*한글-이름*' 같은 식으로 파일을 찾는데 나오지 않을 때가 있어서 괴롭다. macOS의 finder를 사용한다면 이 부분은 파일 이름이 NFC더라도 잘 찾으니 문제가 없겠지만, 터미널에서 필터나 텍스트 처리를 하길 원한다면 이건 쓰기 어렵다. 회사 재직 중에는 이런 파일이름을 재정규화 스크립트를 작성해서 사용했다. 파일 이름이 (내 취향보다) 길어지고 (한글 한 글자당 3바이트가 아니라 9바이트), 자소 단위의 증분검색(incremental search)외에는 큰 이득이 없다고 생각해서 NFC로 다 맞춰서 사용한 것. 퇴사하고 나니 이런걸 처리하는 스크립트가 없어서 어제 다시 작성하려고 끄적여 봤다.

Python의 unicodedata 패키지를 쓰면 아주 간단하게 짤 수 있을 것 같았고, 몇 가지 보호 장치 — dry-run 플래그나 덮어 쓰기 방지 — 를 추가하다가 신기한 경험을 했다. NFD인 이름을 NFC로 재정규화한 이름으로 바꾸기 전에 해당 파일이 있나 검사하면 항상 이미 있다고 나오는 것. 처음에는 HFS+ 수준의 문제라고 추측했는데, 새 맥북이라 APFS를 쓰고 있었고, APFS는 문서 상으로는 파일 이름을 단순 바이트 문자열 + 유효한 코드포인트 제약으로 동작해야 한다. 그렇지만 실제 동작은 그렇지 않은 것. (Linux는 서로 다른 파일로 취급하기 때문에 덮어 쓰기 테스트가 필요하다.)

  • NFC 파일 이름으로 생성한 뒤에 NFD 형식의 이름으로 파일을 열거나 존재하는지 확인하면 성공한다.
  • NFD/NFC를 바꿔서 해봐도 역시 성공한다.

그래서 검색해보니 APFS가 최대한 NFC/NFD 혼동을 줄이기 위한 계층/기능을 하는 듯 하다.

…최종적으론 이거저거 검색하다가 이미 있는 도구를 조합해서 해결할 방법을 찾았다.

우선 파일 / 디렉터리 이름 일괄 변환은 convmv를 사용한다. UTF-8 인코딩을 쓴다치고, 현재 디렉터리 및 그 하위 디렉터리의 파일/디렉터리 이름을 NFC 형식으로 바꾸려면 아래처럼 실행한다.

convmv -r -f utf-8 -t utf-8 --nfc . --notest

권한이나 다른 호환성 문제로 이름을 바꾸는게 불가능하거나 번잡한 경우, find 명령을 활용하기 위해선 아래처럼 할 수 있다.

find . -type f | uconv -x nfc | fzf

이건 “현재 디렉터리 및 그 이하의 파일 이름을 나열하고”, “이름을 NFC로 변환하고”, “이걸 fzf에서 확인"하는 식.