🤐
いますぐ Mac の CLI から Windows で文字化けしない ZIP ファイルを作りたい僕たち私たち
これはなに
- 令和にもなって未だに macOS Finder で zip 作ったら Windows で文字化けして悲しい
- CLI でサクッと Windows / macOS / Linux 全対応の zip ファイルを作りたい
- ありがちな文字化けの原因は以下 2 点らしいので、それぞれ対応したい
- macOS の Unicode 正規化形式 NFD について、一般的な NFC に寄せるのが丸いぽい
- Windows では zip 解凍時のファイル名の解釈の仕様が「UTF-8 フラグがあれば UTF-8 で、なければ OS 標準の CP932 で解釈」になってるらしいので、UTF-8 フラグを付与しないと化け放題になるらしい
参考
ファイルアップロードではNFC/NFD問題に気をつけろ!~MacファイルシステムにおけるUnicode正規化の闇~
Windows と Unicode とボク > DLC3: ZIPファイルと文字化け
macOSのZIPコマンド
シェル関数でがんばる
システム利用ではなく、日常使いで「多くのケースで大丈夫にしたい」程度なので、シェル関数でがんばることにする。
# 文字コードのコンバーターを入れる
$ brew install convmv
# zip を brew で入れ直して --unicode オプションを使えるようにする
$ brew install zip
# パスを設定して macOS 標準 zip から brew で入れた zip を使うようにする
$ which zip # /usr/bin/zip など macOS 標準の zip であることを確認
$ brew link zip # macOS 標準 zip と衝突するため link 生成されず、PATH の書き換えコマンドが例示される
$ echo 'export PATH="/usr/local/opt/zip/bin:$PATH"' >> ~/.zshrc # ↑ の例示通り実行、環境による
$ which zip # この例では /usr/local/opt/zip/bin/zip のように brew で入れたものになるはず
ここまでやったら以下 shell function を .zshrc とかに登録。
# safezip - どの OS でも文字化けしないよう NFC / UTF-8 な zip を作成する
# brew install convmv で convmv コマンド実行でき
# brew install zip で zip を入れ直して PATH を通している前提
# e.g.) $ safezip src/ [out.zip]
safezip() (
set -euo pipefail
src="${1%/}"
out="${2:-${src##*/}.zip}"
base="${src##*/}"
[ -e "$src" ] || { echo "❌ Not found: $src" >&2; exit 1; }
# 出力先のパス解決のがんばり
dest_dir="$(dirname -- "$out")"
dest_name="$(basename -- "$out")"
if [ "$dest_dir" = "." ]; then
dest="$PWD/$dest_name"
else
dest="$(cd "$dest_dir" && pwd -P)/$dest_name"
fi
# 文字コード変換を非破壊的にやりたいから tmp でうにょってるだけ
tmp="$(mktemp -d "${TMPDIR:-/tmp}/safezip.XXXXXX")"
trap 'rm -rf -- "$tmp"' EXIT
if [ -d "$src" ]; then
mkdir -p "$tmp/$base" && cp -R "$src"/. "$tmp/$base"/
else
cp "$src" "$tmp/$base"
fi
cd "$tmp"
# convmv の --nfc で NFC 正規化へコンバート
# コンバート時にエンコーディング指定が必要なので -f utf-8 -t utf-8 をつけてる
convmv -r -f utf-8 -t utf-8 --notest --nfc "$base"
# -UN が --unicode オプション、ここで UTF-8 フラグをつけてる
# ついでにありがちな .DS_Store とか消したり
zip -r -X -UN=UTF8 "$dest" "$base" -x "*/.DS_Store" "*/__MACOSX/*"
echo "✅ Generated: $dest"
)
つかいかた
ターミナル再起動して読み込んだら、こんな感じで使えるはず。
$ safezip target/ # ✅ Generated: ~/target.zip
... 面倒だ、OS 側でなんとかしてくれ。。。
Discussion