Ubuntuでzipを展開した時の文字化けを回避する

※2017年5月24日、バージョンアップ。

Windowsで内部に日本語を含むzipファイルを作成して、それをWindows以外のOSで解凍すると文字化けする、という話はMacユーザーやLinuxユーザーの間では広く知られていると思われる面倒くさいバグなのだが、今回その文字化けを何とかしてみようと思い、Nautilus用のスクリプトを作成してみた。
何で既に回避策が存在するのにそんなもの作ろうと思ったのか、という点についても一応下の方に書いておく。

スクリプトのダウンロードとインストー

まず以下のリンクをクリックするなどしてunarなどをインストールする。
apt:unar
apt:unrar
apt:p7zip-full

#コマンドを使う場合はこうする
sudo apt install -y unar unrar p7zip-full 

次に端末(gnome-terminal)を起動して、以下のコマンドを実行する。

cd ~/.local/share/nautilus/scripts/ && wget http://sicklylife.at-ninja.jp/memo/zip_mojibake_kaihi && chmod +x zip_mojibake_kaihi && mv zip_mojibake_kaihi zipを展開する\(文字化け回避\) && cd - 

するとファイル(Nautilus)の右クリックメニューにスクリプト > zipを展開する(文字化け回避)というメニューが追加されるので、zipファイルを右クリックしてそれをクリックすると、Windowsで作成したzipが文字化けすることなく展開される。
f:id:sicklylife:20170503125543p:plain

スクリプトを作った理由

Ubuntuでのzipの文字化け対策と言えば、Ubuntu Japanese Teamの日本語Remixを使うか、Ubuntu Japanese Teamのppaを使う方法が一般的だと思われるのだが、現在私が使用しているUbuntu GNOME 17.04 + Nautilus 3.24.1では以前と仕様が変わったらしく、Ubuntu Japanese Teamの文字化け回避策 (/etc/profile.d/unzip-default-charset.sh) を適用しても文字化けが直らないようになってしまっている。
f:id:sicklylife:20170503130159p:plain
Nautilus 3.24.1では↑このスクショのようにExtract Here(ここに展開する)がデフォルトになって、zip/7z/xzなどの圧縮ファイルをダブルクリックするとその場に展開されるようになり、しかも関連付けを変更しても反映されないという糞仕様になってしまっている。
file-rollerを起動してzipを開いて展開すれば(文字化け回避策を適用していれば)文字化けせずに展開されるが、いちいちfile-rollerを起動するのも面倒だし、右クリックからサクッと展開したかったのでスクリプト化してみた。来年のLTSまでに修正されるといいなぁ。

↓以下はスクリプトの中身。

#!/bin/bash
# unarでアーカイブを展開
#
# バージョン: 0.0.2
# ライセンス: GPLv2
# 作者      : Sickly Life
# 日時      : 2017年5月24日
# 備考      : unarだと文字化けが直らない場合があったのでunzipを使うように修正。
#             パスワードには未対応。
#             7zファイルは7zコマンドで展開するようにしているが、ほぼ未テスト。
# 参考      : shとbashでの変数内の文字列置換など - ろば電子が詰まっている (http://d.hatena.ne.jp/ozuma/20130928/1380380390)

RMFILE=/tmp/file.YcZCaYDRKQm3us9fFyTBphd9zYeycwRKFPKGCPvMSNejW4rF2EYaHKEiTAkhDmcjTWSaXxQtBh8AFrhXPNqiVcx8vJrZFZGR2kXosxGsWqdHPfLhMmhoj2f9QVS2ByLCWkkAQgtx3pR3oQXyTkZQc79Cg2uCVcYQ6Bx4CGCiczoEQrWsQe6kDeYoHPKoRww4kMPYpAxe*
TMPFILE=/tmp/file.YcZCaYDRKQm3us9fFyTBphd9zYeycwRKFPKGCPvMSNejW4rF2EYaHKEiTAkhDmcjTWSaXxQtBh8AFrhXPNqiVcx8vJrZFZGR2kXosxGsWqdHPfLhMmhoj2f9QVS2ByLCWkkAQgtx3pR3oQXyTkZQc79Cg2uCVcYQ6Bx4CGCiczoEQrWsQe6kDeYoHPKoRww4kMPYpAxe.$$
UNZIP_LOG_FILE=/tmp/file.YcZCaYDRKQm3us9fFyTBphd9zYeycwRKFPKGCPvMSNejW4rF2EYaHKEiTAkhDmcjTWSaXxQtBh8AFrhXPNqiVcx8vJrZFZGR2kXosxGsWqdHPfLhMmhoj2f9QVS2ByLCWkkAQgtx3pR3oQXyTkZQc79Cg2uCVcYQ6Bx4CGCiczoEQrWsQe6kDeYoHPKoRww4kMPYpAxe.unzip

rm -f $RMFILE

trap 'kill $(jobs -p); zenity --text-info --filename=$TMPFILE --title=展開終了 --width=600 --height=400; rm -f $TMPFILE; kill $$' EXIT
trap 'kill $(jobs -p); zenity --text-info --filename=$TMPFILE --title=展開終了 --width=600 --height=400; rm -f $TMPFILE; kill $$' ERR

if [ $# -gt 100 ]; then
    echo "ファイルの数が多すぎます。一度に展開できるファイル数の上限は100です。" &>> "$TMPFILE"
    exit 0
else
    declare -i num=$((100/$#))
fi

declare -i count=0

for arg
do
    name="${arg%.*}"
    ext="${arg##*.}"

    if [ "${ext,,}" = 'zip' ]; then
        unzip -Z -- "$arg" &>> "$UNZIP_LOG_FILE"
        grep 'number of entries: 1' "$UNZIP_LOG_FILE"; result=$?
        if [ "$result" = 0 ]; then
            truncate -s 0 "$UNZIP_LOG_FILE"
            unzip -o -O sjis -- "$arg" &>> "$TMPFILE"
        else
            sed -n '3p' "$UNZIP_LOG_FILE" | grep -E '^d'; result=$?
            if [ "$result" = 0 ]; then
                truncate -s 0 "$UNZIP_LOG_FILE"
                unzip -o -O sjis -- "$arg" &>> "$TMPFILE"
            else
                truncate -s 0 "$UNZIP_LOG_FILE"
                unzip -o -d "$name" -O sjis -- "$arg" &>> "$TMPFILE"
            fi
        fi
    elif [ "${ext,,}" = 'rar' ]; then
        unrar x -v -- "$arg" &>> "$TMPFILE"
    elif [ "${ext,,}" = '7z' ]; then
        7z x -- "$arg" &>> "$TMPFILE"
    else
        unar -- "$arg" &>> "$TMPFILE"
    fi

    echo >> $TMPFILE
    # unrar & unar
    sed -i "/... OK.\$/d" "$TMPFILE"
    # unrar
    sed -i "/All OK\$/d" "$TMPFILE"
    # unzip
    sed -i "/^   creating: /d" "$TMPFILE"
    sed -i "/^  inflating: /d" "$TMPFILE"

    count=$(($count+$num))
    echo "$count"
done | \
zenity \
    --progress \
    --title="展開" \
    --text="ファイルを展開中..." \
    --percentage=0 \
    --auto-close \
    --auto-kill

exit 0
#!/bin/bash
# unarでアーカイブを展開
#
# バージョン: 0.0.1
# ライセンス: GPLv2
# 作者      : Sickly Life
# 日時      : 2017年5月3日
# 参考      : shとbashでの変数内の文字列置換など - ろば電子が詰まっている (http://d.hatena.ne.jp/ozuma/20130928/1380380390)

RMFILE=/tmp/unar.YcZCaYDRKQm3us9fFyTBphd9zYeycwRKFPKGCPvMSNejW4rF2EYaHKEiTAkhDmcjTWSaXxQtBh8AFrhXPNqiVcx8vJrZFZGR2kXosxGsWqdHPfLhMmhoj2f9QVS2ByLCWkkAQgtx3pR3oQXyTkZQc79Cg2uCVcYQ6Bx4CGCiczoEQrWsQe6kDeYoHPKoRww4kMPYpAxe*
TMPFILE=/tmp/unar.YcZCaYDRKQm3us9fFyTBphd9zYeycwRKFPKGCPvMSNejW4rF2EYaHKEiTAkhDmcjTWSaXxQtBh8AFrhXPNqiVcx8vJrZFZGR2kXosxGsWqdHPfLhMmhoj2f9QVS2ByLCWkkAQgtx3pR3oQXyTkZQc79Cg2uCVcYQ6Bx4CGCiczoEQrWsQe6kDeYoHPKoRww4kMPYpAxe.$$

rm -f $RMFILE

trap 'kill $(jobs -p); zenity --text-info --filename=$TMPFILE --title=展開終了 --width=600 --height=400; rm -f $TMPFILE; kill $$' EXIT
trap 'kill $(jobs -p); zenity --text-info --filename=$TMPFILE --title=展開終了 --width=600 --height=400; rm -f $TMPFILE; kill $$' ERR

declare -i num=$((100/$#))
declare -i count=0

for arg
do
    ext="${arg##*.}"

    if [$ext = "rar"]; then
        unrar xv -- "$arg" &>> $TMPFILE
    else
        unar -- "$arg" &>> $TMPFILE
    fi

    echo >> $TMPFILE
    sed -i "/... OK.\$/d" $TMPFILE
    count=$(($count+$num))
    echo $count
done | \
zenity \
    --progress \
    --title="展開" \
    --text="ファイルを展開中..." \
    --percentage=0 \
    --auto-close \
    --auto-kill

exit 0