LoginSignup
10
4

macOSのターミナル(zsh)を使ってWindowsで文字化けしないZIPファイルを作る

Posted at

要点

  • Windowsで解凍しても文字化けしない
  • .DS_Store 等の不要な隠しファイルを含まない1

上記2点を満たしたZIPファイルをコマンドラインシェル(zsh)から作成します.

きっかけ

macOSでZIPファイルを作成する際にはFinderの「圧縮」機能を利用できます.
しかしこの方法で作成したZIPファイルは,Windows PCへ送付した場合に困ることが二つあります.

その1.ファイル名が文字化けする
macOSで作成したZIPファイルをWindowsで解凍すると,ファイル名に含まれる日本語が文字化けしてしまいます.
これはmacOSとWindowsで用いられる文字コードが異なるために起きます2
Windows上で作ったZIPファイルはmacOSで開いても大丈夫なのに逆はダメなので,仕方ないですが Windowsで解凍しても文字化けしないZIPファイルを作成したいところです.

その2.不要なファイルが入る
macOSでは.DS_StoreのようなOS固有のファイルが自動で生成されます.
macOS上では隠しファイルになっているため,不要であるにも関わらずZIPファイルへの圧縮時に含めてしまうことがあります.
そのままWindowsユーザに送付するとお小言をいただくので,仕方ないですが このような他OSでは不要なファイルを除いた状態でZIPファイルを作成したいです.

利用するソフト

今回は

  • fd: rust製findコマンド
  • p7zip: コマンドライン版7-Zip

の2つのソフトを利用します.
どちらもHomebrewを利用してインストールできます.

brew install fd
brew install p7zip

指定したフォルダをZIPファイルに圧縮する

現在の作業ディレクトリ直下にあるディレクトリ./targettarget.zipという名前で圧縮しましょう.
次のコマンドを実行すれば,きっとうまく行くはずです.

fd --type file . target -X 7z a -tzip -scsWIN target.zip {}

以下ではこのコマンドがどのように動いているのか解説します.

Windowsで文字化けしないZIPファイルを作る

p7zip3を用いてWindowsで文字化けしないzipファイルを作成するコマンドは

7z a -tzip -scsWIN 出力ファイル名 圧縮するファイル・ディレクトリ

です.
重要なのが-scsWINオプションです.
-scsSet charset for list files のことで,-scsWINとすることでWindowsの文字コードに合わせてくれます.

また7z a コマンドは通常7-Zip形式の圧縮ファイルを作成しますが,-tzipオプションを利用することで出力ファイルの形式をZIPファイルに変更できます.

2023年夏頃から,Windowsに標準搭載されているエクスプローラで7-Zipファイルの解凍可能になりました4
なので7-Zip形式のままでも一応大丈夫ですが,今回はWindowsで一般的に利用されるZIP形式で作成します.

隠しファイルを取り除く

fdコマンドを利用して隠しファイルを取り除きます.

fd --type file . 対象のディレクトリ

で指定したディレクトリ以下に存在するファイルを検索します.
この際,デフォルトでは隠しファイルは検索結果に含まないので5.DS_Store等の不要なファイルを弾くことができます.
デフォルトではファイルとディレクトリの両方を表示するので,--type fileオプションでファイルのみを検索するよう指定します.

これに加えて-Xオプション6を追加することで検索結果にコマンドを実行できます.
fdによる検索結果を利用するには,実行したいコマンドのファイル名を指定する箇所に{}を記述します.
具体的に

fd --type file . 圧縮したいディレクトリ名 -X 7z a 出力ファイル名.zip {}

とすることで,fdが圧縮したいディレクトリ以下に含まれるファイルを検索し,その結果が{}で記述した7z aコマンドの圧縮対象のファイル指定部分に適用されます.

以上のことを組み合わせることで,隠しファイルを取り除きながらWindowsでも文字化けしないZIPファイルを作成できます.

zshの関数にまとめる

先ほどのコマンドを毎回入力するのは面倒!という人は,zshの関数にまとめて.zshrcに記述しておきましょう.
ディレクトリ名を指定し,当該ディレクトリ以下のファイルをZIPファイルに圧縮する関数は以下の通りです.

function zipwin () 
{
  if [ -z $1 ] || [ $1 = . ]; then
    # 現在の作業ディレクトリをZIPファイルに圧縮する.
    local zip_name="$(basename $(pwd)).zip"
    fd --type file --strip-cwd-prefix . -X 7z a -tzip -scsWIN $zip_name {}
  else
    # 指定したディレクトリをZIPファイルに圧縮する.
    local loc_dir=$(dirname $1)
    local target=$(basename $1)
    local zip_name="$(pwd)/${target}.zip"
    fd --type file --base-directory=$loc_dir . $target -X 7z a -tzip -scsWIN $zip_name {}
  fi

  # 作成したZIPファイルに含まれるファイルを確認する.不要であればコメントアウトしてください.
  7z l $zip_name

  return 0
}

上記の関数を用意すれば

zipwin 圧縮したいディレクトリ

で指定したディレクトリをWindowsでも文字化けしないZIPファイルに圧縮できます.

引数がない場合,あるいは.(作業ディレクトリ)を指定した場合は,作業ディレクトリ以下のファイルをZIPファイルに圧縮するようにしています(if文のtrueの方ですね).
ここでfd--strip-cwd-prefixオプションを追加しています.
作業ディレクトリを対象にfdで検索をかけると,検索結果のファイルパス最初に./が付きます.
そのまま7z aコマンドに流し込むと,ディレクトリ構造が壊れて全てのファイルが同じディレクトリに保存されてしまいます.
そこで検索結果から./を取り除くオプションである--strip-cwd-prefixを追加しました.

また,ディレクトリを指定した場合(else以降の方)は--base-directory=オプションを追加しています.
例えばfd . hoge/fugaのようにサブディレクトリであるfugaを検索対象にした場合,検索結果のファイルパスにはhoge/fuga/piyo.txtのようにhogeディレクトリの名前が含まれます.
そのまま7z aコマンドに流すとZIPファイルの圧縮結果に不要な階層(hoge)が生じます.
そこで--base-directoryオプションで検索結果の表示で起点となるディレクトリを指定し,不要な階層を取り除くようにしました.

最後におまけで,7z lコマンドを利用して圧縮したファイル一覧を表示するようにしています.

以上です.
ご覧いただきありがとうございました.

  1. 今回の方法では全ての隠しファイルを取り除いてZIPファイルを作成します.隠しファイルも含めてZIPファイルを作成する場合は,.DS_Store等の不要なファイルをピンポイントに取り除くような別の方法を利用してください.

  2. macOSはUTF-8,WindowsはShift-JISを利用.

  3. p7zipのシェルスクリプト上での実行コマンドは7zです.

  4. 参考:https://pc.watch.impress.co.jp/docs/topic/feature/1513517.html

  5. -Hオプションを加えることで隠しファイルを検索対象に含めることができます.

  6. fdのオプションには-x(小文字)と-X(大文字)があります.どちらも検索結果に指定したコマンドを実行しますが,小文字だと「検索結果に対して個別に処理」,大文字だと「検索結果に対してバッチ処理」です.

10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4