LoginSignup
13
11

More than 5 years have passed since last update.

ディスク容量節約:tar.bz2やtar.gzをtar.xzに変更するスクリプト&解説

Last updated at Posted at 2014-03-13

あらまし

先日、Jenkins で保存していたビルド成果物がディスク領域を圧迫してしまい、Jenkinsが止まってしまいました。
早急にディスク領域を空けないとプロジェクトに支障をきたしてしまいます。

成果物をfoo.tar.bz2のように、tar+bzip2形式で保存したので、これをより圧縮率の高いtar+xz形式に変換することで、ディスク領域を空けることができました。

本題

Linuxカーネルのソースコードを使って、実際にやってみましょう。

.tar.bz2の場合

recompress-bz2.sh に tar+bzip2形式のファイルを食わせればOKです。

recompress-bz2.sh
#!/bin/bash -ue

BZ2=$1
XZ=${1%.bz2}.xz

trap "echo $0 trapped.; rm -f $XZ" 1 2 3 15

if bzcat $BZ2 | xz -v > $XZ
then
    trap "echo $0 trapped." 1 2 3 15
    rm -f $BZ2
else
    rm -f $XZ
fi
.tar.bz2の場合
$ wget https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.12.tar.bz2
$ ls -lh linux-3.12.tar.bz2
-rw-r--r-- 1 hogefoo hogefoo 87M 11月  4 08:47 linux-3.12.tar.bz2
$ sh recompress-bz2.sh linux-3.12.tar.bz2
  100 %        75.2 MiB / 518.8 MiB = 0.145   2.0 MiB/s       4:16             
$ ls -lh linux-3.12.tar.*
-rw-r--r-- 1 hogefoo hogefoo 76M  3月 14 01:00 linux-3.12.tar.xz

もとの.tar.bz2ファイルは消え、.tar.xzファイルができています。
容量はざっと 11MB減りました

.tar.gzの場合

.tar.bz2の場合とあんまり変わりません。

recompress-gz.sh
#!/bin/bash -ue

GZ=$1
XZ=${1%.gz}.xz

trap "echo $0 trapped.; rm -f $XZ" 1 2 3 15

if zcat $GZ | xz -v > $XZ
then
    trap "echo $0 trapped." 1 2 3 15
    rm -f $GZ
else
    rm -f $XZ
fi
tar.gzの場合
$ wget https://www.kernel.org/pub/linux/kernel/v3.0/linux-3.12.tar.gz
$ ls -lh linux-3.12.tar.gz
-rw-r--r-- 1 hogefoo hogefoo 110M 11月  4 08:47 linux-3.12.tar.gz
$ sh recompress-gz.sh linux-3.12.tar.gz
  100 %        75.2 MiB / 518.8 MiB = 0.145   2.0 MiB/s       4:13             
$ ls -lh linux-3.12.tar.*
-rw-r--r-- 1 hogefoo hogefoo 76M  3月 14 01:17 linux-3.12.tar.xz

こちらは34MB減っています

解説

tar形式

そもそも、foo.tar.bz2というのは、foo.tarというtar形式のファイルをbzip2で圧縮したファイルです。
tar形式に圧縮機能はなく、コンテナとしてファイルとそのメタ情報を記録する機能しかありません

なのでbzip2やgzipの圧縮から解いて、ただのtar形式にしてからxzで圧縮すれば、tar.xzの出来上がりです。

tar.bz2やtar.gzからtarへ

bzcatzcatを用いると、 簡単に.tar.bz2 や.tar.gzをtar形式として標準出力に流す ことができます。

$ bzcat foo.tar.bz2 > foo.tar
$ zcat bar.tar.gz > bar.tar

tarからtar.xzへ

xz -で、 標準入力をxzで圧縮して標準出力に流すことができます

$ cat foo.tar | xz - > foo.tar.xz

recompress-bz2.shrecompress-gz.shでは、-vを付けて、進捗を表示させています。

tar.bz2やtar.gz から、tar.xzへ

標準出力へtar形式を流す方法と、標準入力をxzで圧縮する方法がわかりました。
あとはくっつけるだけです。

$ bzcat foo.tar.bz2 | xz - > foo.tar.xz
$ zcat bar.tar.gz | xz - > bar.tar.xz

おしまい。

蛇足

拡張子

Bashの機能を用いて、拡張子の変換を行ってます。
POSIX Shellでできるかどうかは調べてません。

追記 コメント欄より

POSIX シェルでも出来ます!

とのことです。THX! @magicant

GZ=$1
XZ=${1%.gz}.xz

${1%.gz}$1の末尾から.gzを削った結果を返します。

Ctrl-Cの対応

trapを用いて、Ctrl-Cで止められた時の処理をしています。

Linuxの場合
trap "echo $0 trapped.; rm -f $XZ" 1 2 3 15

または

他OSではシグナルの番号が違うことがあるので名前で指定
trap "echo $0 trapped.; rm -f $XZ" HUP INT QUIT TERM

第一引数はシグナルを受けたときに実行する処理、
第二引数はシグナルを示しています。

ここでシグナルは番号、名前の両方が使えますが、
OSによって番号がは異なることがあるため、名前を用いた方が移植性が高いようです。
コメント欄参照。 THX! @magicant

$ kill -l
 1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX    

一般的に、1 2 3 15をおさえておけばよいそうです。

また、再圧縮が終わってrm -rf $GZする前にtrap "echo $0 trapped." 1 2 3 15として、削除処理上書きして無効にすることで、せっかく出来たtar.xzファイルを削除してしまわないようにしています。

他の方法

tar xvzfなりtar xvjfなりで解凍してからtar xvJfで圧縮することもできますが、
ディスク領域と時間の無駄なのであんまりオススメできません。

参考

trapについては、以下を参考にしました。
シグナルと trap コマンド - UNIX & Linux コマンド・シェルスクリプト リファレンス

#!/bin/bash -ueについては、 @youcune の以下の記事を参考にしました
シェルスクリプトを書くときはset -euしておく

bash, bzcat, zcat, xzについては、man bash, man bzip2, man gzip, man xzを参考にしました。

おことわり

異常処理とか適当なので、データ消失等の事故については自己責任でおねがいします。
もし危ないところに気づいたら編集リクエストなりコメントなりで御指摘いただけると幸いです。

また、語の統一がかなり適当なので、あとで編集するかもです。
大意は変わらないはずです。

あしからず。

13
11
3

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
13
11