pslaboが試したことの記録

はてなダイヤリーからはてなブログに引っ越してきました

この日記は現在実行中の減量記録を含む個人的なメモとして始めましたが、最近はコンピュータやガジェット、ハック、セキュリティネタのほうがメインになっております。

はてなダイヤリー時代はカテゴリ分けが適当だったのですが、これはそのうち直します。


ストレージ内の gzip や bzip2 の圧縮済みファイルを xz に変換する


ストレージの容量が厳しくなってきたので以下のようなコマンド実行で gzip 等のアーカイブを xz に一括変換してくれるスクリプトを書いてみた。

find . -type f -name '*.gz' | xargs convert2xz
  • user, group は root で実行した場合に引き継がれます。
  • 同名の *.xz と *.gz が存在した場合は、タイムスタンプが違う場合だけ書き潰します。
#!/bin/sh

# 圧縮ファイルを xz で再圧縮する処理。

which pv > /dev/null 2>&1
if [ $? -eq 0 ]; then
        PV="pv"
else
        PV=""
fi


while [ $# -gt 0 ]; do
        FILE=$1 ; shift

        if [ ! -e "${FILE}" ]; then
                continue
        fi

        # 元ファイルの拡張子を取得する(大文字 -> 小文字変換込み)
        EXT=$( echo ${FILE##*.} | tr "[:upper:]" "[:lower:]" )

        # 拡張子毎の展開プログラムを決定する。
        case "${EXT}" in
                "gz" )  EXTCMD="zcat"  ;;
                "bz2" ) EXTCMD="bzcat" ;;
                "tgz" ) EXTCMD="zcat"  ;;
                "tbz" ) EXTCMD="tbz"   ;;
                * )     EXTCMD=""      ;;
        esac

        case "${EXT}" in
                        "gz"  ) EXTCMD="zcat";  EXT_XZ="xz" ;;
                        "bz2" ) EXTCMD="bzcat"; EXT_XZ="xz" ;;
                        "tgz" ) EXTCMD="zcat";  EXT_XZ="txz" ;;
                        "tbz" ) EXTCMD="bzcat"; EXT_XZ="txz" ;;

                        "xz"  ) continue ;;
                        "txz" ) continue ;;

                        * ) EXTCMD=""; EXT_XZ="xz" ;;
        esac

        echo "$FILE     "

        if [ "${EXTCMD}" == "" ]; then
                # 展開用プログラムが不定の場合は処理対象外。
                echo "ignore"
        else
                # 実行フラグを立てる(途中の処理でこれを落とす場合あり)
                EXEC_XZ_FLAG=1

                # 元ファイル名の拡張子を .xz に変更したファイル名を作る
                FILE_XZ=${FILE%.${EXT}}.$EXT_XZ

                # .xz なファイルが存在している場合は
                # タイムスタンプが違う場合だけ処理対象とする。
                if [ -e $FILE_XZ ]; then
                        TIMESTAMP_ORG=$( date --reference=$FILE      +"%s" )
                        TIMESTAMP_DST=$( date --reference=$FILE_XZ   +"%s" )

                        echo $TIMESTAMP_ORG
                        echo $TIMESTAMP_DST

                        if [ $TIMESTAMP_ORG -eq $TIMESTAMP_DST ]; then
                                $EXEC_XZ_FLAG=0
                        fi
                fi

                # 実行フラグが立っていたら再圧縮処理を実施
                if [ $EXEC_XZ_FLAG -eq 0 ]; then
                        echo "skip: already compressed."
                else
                        trap "rm -f $FILE_XZ ; exit 1" 0 1 2 3 13 15

                        if [ "${PV}" == "" ]; then
                                           $EXTCMD $FILE | xz -v > $FILE_XZ
                        else
                                pv $FILE | $EXTCMD       | xz    > $FILE_XZ
                        fi

                        trap "exit 1" 0 1 2 3 13 15
                fi

                # 再圧縮前後の状態の md5sum を比較し、
                # 合致した場合はオリジナルを消す。
                # 合致しない場合は xz 形式のファイルを消す。
                tmpfile=$( mktemp )
                trap "rm -f $tmpfile ; exit 1" 0 1 2 3 13 15

                $EXTCMD $FILE      | md5sum                 > $tmpfile
                xzcat   $FILE_XZ   | md5sum --quiet --check   $tmpfile

                if [ $? -eq 0 ]; then
                        touch --reference=$FILE $FILE_XZ
                        chmod --reference=$FILE $FILE_XZ

                        owner_orig=$( stat --printf="%u" $FILE )
                        if [ ${UID} -eq $owner_orig ]; then
                                # このスクリプトの実行ユーザと元ファイルの owner が
                                # 一致する場合は、group を元ファイルに合わせる。
                                chgrp --reference=$FILE $FILE_XZ
                        elif [ ${UID} -eq 0 ]; then
                                # このスクリプトの実行ユーザが root の場合は
                                # owner , group を元ファイルに合わせる。
                                chown --reference=$FILE $FILE_XZ
                                chgrp --reference=$FILE $FILE_XZ
                        fi

                        echo -n "${FILE##*/} "
                        stat --printf="%s byte -> " $FILE
                        stat --printf="%s byte\n\n"   $FILE_XZ
                        rm -f $FILE
                else
                        if [ $EXEC_XZ_FLAG -ne 0 ]; then
                                rm -f $FILE_XZ
                        fi
                fi

                rm $( mktemp )
                trap "exit 1" 0 1 2 3 13 15
        fi
done