rsync でファイル名が文字化けするときの対処(–iconv と macOS の NFD 問題)

Mac から Linux サーバへ rsync でファイルを送ったら、日本語ファイル名の濁点・半濁点が分離して「テ゛ータ」のようになった。検索やタブ補完でファイル名がヒットしない。同期し直すたびに全ファイルが再転送される。こうした症状は、文字コードそのものではなく Unicode の正規化形式(NFC/NFD)の違いが原因です。

結論から言うと、Mac 側の rsync に --iconv オプションを付けて、転送時にファイル名を変換するのが定番の解決策です。

# Mac から Linux へ(push でも pull でもこの指定でOK)
rsync -a --iconv=utf-8-mac,utf-8 ~/data/ user@linux-server:/path/to/data/

ただし macOS に最初から入っている /usr/bin/rsync ではこのオプションが使えません(後述)。Homebrew で本家 rsync を入れてから実行してください。

brew install rsync

何が起きているのか:NFC と NFD

「デ」という1文字は、Unicode では2通りの表現ができます。

  • NFC(合成形): 「デ」1文字。バイト列は E3 83 87
  • NFD(分解形): 「テ」+「結合濁点」の2文字。バイト列は E3 83 86 + E3 82 99

見た目はどちらも「デ」ですが、バイト列としては別物です。Linux では NFC でファイル名を付けるのが普通なのに対し、Mac は伝統的に NFD を使います(かつての標準ファイルシステム HFS+ がファイル名を強制的に NFD 相当へ分解して保存する仕様でした。現在の APFS は分解こそ強制しませんが、macOS 上で作られたファイルには今も NFD 名が広く存在します)。

rsync はファイル名をただのバイト列として運ぶので、Mac の NFD 名はそのまま Linux に持ち込まれます。その結果、

  • 端末やアプリによっては濁点が分離して「テ゛」のように表示される
  • NFC で入力した検索文字列と一致しない(ls | grep デ がヒットしない)
  • NFC 名の同名ファイルと共存してしまい「同じ名前が2つある」状態になる

といった症状になります。

–iconv でファイル名を変換する

rsync 3.0 以降には、転送時にファイル名の文字コードを変換する --iconv=ローカル,リモート オプションがあります。Mac 側の文字コードとして utf-8-mac(NFD を扱う libiconv の特殊指定)を指定すると、NFD⇄NFC を変換しながら転送してくれます。

# Mac がローカル、Linux がリモートの場合
rsync -a --iconv=utf-8-mac,utf-8 src/ user@server:/path/to/dst/

指定は「ローカル,リモート」の順で固定なので、同じ書き方のまま push(Mac→Linux)でも pull(Linux→Mac)でも正しく動きます。

手元の rsync 3.4.4 で、NFD 名のファイル(「デ」が E3 83 86 E3 82 99)を --iconv=utf-8-mac,utf-8 付きでコピーして確認すると、コピー先のファイル名は NFC(E3 83 87)に変換されていました。ファイル名のバイト列は ls | xxdls | hexdump -C で確認できます。

注意点がいくつかあります。

  • 変換はファイル名だけが対象です。ファイルの中身の文字コードは変換されません。
  • リモート転送では両端の rsync が iconv 対応(3.x)である必要があります。接続先の rsync が古いと使えません。
  • 変換できない文字が混ざっていると cannot convert filename(終了コード 23)で該当ファイルがスキップされます。詳しくは rsync の終了コード一覧と意味 を参照してください。

罠:macOS 標準の rsync では –iconv が使えない

macOS Sequoia 15.4(2025年4月)から、/usr/bin/rsync の実体はライセンス上の理由で本家 rsync ではなく openrsync(BSD ライセンスの別実装)に置き換えられています。rsync --version で確認できます。

$ /usr/bin/rsync --version
openrsync: protocol version 29
rsync version 2.6.9 compatible

openrsync は --iconv に対応しておらず、指定すると unrecognized option になります(手元の macOS で確認)。--iconv を使いたい場合は Homebrew の rsync(3.x)を使ってください。brew install rsync 後、パスの通し方によっては /opt/homebrew/bin/rsync(Intel Mac では /usr/local/bin/rsync)をフルパスで指定するのが確実です。

なお置き換え前の macOS に入っていた Apple 版 rsync も 2.6.9 ベースで --iconv 非対応だったので、「Mac 標準の rsync では使えない」という状況は実は昔から変わっていません。

すでに NFD 名で転送してしまったファイルの直し方

Linux 側に NFD 名のファイルができてしまった後からでも、convmv コマンドで一括正規化できます。

# まず --notest なしで実行して変更内容をプレビュー
convmv -r -f utf-8 -t utf-8 --nfc /path/to/dir
# 問題なければ --notest を付けて実際にリネーム
convmv -r -f utf-8 -t utf-8 --nfc --notest /path/to/dir

Debian/Ubuntu なら apt install convmv、Fedora なら dnf install convmv で入ります(RHEL 系は EPEL リポジトリを有効にしてから)。既定ではプレビューのみで、--notest を付けたときだけ実際に変更される安全設計です。

Windows(Cygwin)の場合

かつて(2009年頃まで)は Cygwin 版 rsync が日本語ファイル名の変換に失敗して file has vanishedopendir failed を出す問題があり、パッチ版の cygwin1.dll に差し替える対処が知られていました。これは Cygwin 1.7(2009年12月)でロケールベースの文字コード処理が入り UTF-8 がデフォルトになったことで解消済みです。現在の Cygwin で文字コードを指定したい場合は LANGLC_ALL 環境変数で制御します。また、いまの Windows なら WSL 上の rsync を使うほうが話が単純です(通常の Linux として振る舞います)。

この経緯の詳細と、file has vanished 警告そのものの意味は rsync の「file has vanished」警告(code 24)の意味と対処 にまとめています。

さいごに

Mac⇄Linux のファイル名化けは NFC/NFD の違いが原因で、Homebrew の rsync + --iconv=utf-8-mac,utf-8 で転送時に解決できます。macOS 標準の rsync(openrsync)では使えない点だけ注意してください。転送済みのファイルは convmv で直せます。

あわせて読みたい: