shell scriptで自己解凍書庫
Created , Modified .
* この記事はZennに寄稿した記事を自ら再構成したものである.
結果
Code 1. self-extract-script.sh
shell scriptで自己解凍式の書庫ファイルを作成した. -x
オプションをつけて実行すると以下のことを行う.
- 自身の終端のbase64部分のMD5を表示し, 確認を求める. 拒否すれば, ここで終了する.
- 上記を許可した後, 自身の名前のディレクトリを作成する.
- 自身の終端のbase64部分をデコードしながら, 作成したディレクトリにtar.gzを展開する.
- 展開した根に
autorun.sh
が存在した場合, 実行許可を求める. -
- 拒否した場合, または
autorun.sh
がない場合は終了する. - 許可すると,
autorun.sh
を実行して終了する.
- 拒否した場合, または
動機
たまたま見かけたの終わりの部分に興味を持ったことによる. Cite 1にその記事からの引用を示す.
Cite 1. 自己追記によるFizzBuzz ()
しかし、シェルがスクリプトを一括ではなく逐次読み込みしかしないという性質は実は重要で、これにより以下のようなスクリプトが動作するようになる。
#!/bin/sh
sed 1,/^exit/d $0 | tar xvzf -
exit $?
(tar+gzipアーカイブをバイナリのままここに貼り付け)
(略)
すなわちシェルによる自己展開アーカイブである。
調べてみれば確かに古くからあるし, 今までも至って当然のように利用していたのだろうと思う. ただ, そうであると認識していなかった. ここで示されているようにどうやらbinaryとして作られることが多いようであるため, 恐らく気にも止めずに実行権限を与えていたのだろう.
しかし, あると知ってしまったなら試す他あるまい. そして, どうせ作るなら(逐次読み込みだからそんなことをする必要はないと述べているのに), shell checkがまぁまぁ通るようにshell側へ寄せて書こうと思った次第である.
原理
アーカイブの格納と展開
繰り返しだが, 基本はCite 1の引用と同じである. アーカイブはbase64エンコードしたtar.gzのbinaryをshellのヒアドキュメントを利用してコメントアウトし, exit 0
のさらに下に配置している. これならエディターではテキストして読み込むことができ, 実行時には決して到達しない. アーカイブを取り出すときには前後のヒアドキュメントの囲みを追加したsed
で削ぎ落とし, base64デコードしたものをtar
で展開する.
base64デコード
このテンプレートはbase64デコードにbase64
コマンドを利用していない. shell関数を定義して行っている. sed
の塊が巨大に見えるだろうけれども, やっていることは単純に 1. 各ascii文字に対応する6bitの01に変換する, 2. 連結と挿入によりprintf
の8進数出力表記に整形する, 3. printf
でbinaryを吐く, の3工程である. このやり口はシェルスクリプトはバイナリを扱えない。さてどうしよう……をパクったものである.[*1]
所感, その他
結局, 作成時の手間が増えて利便性がさほど上がっていないものが出来上がってしまった. 一応の利点は(多分)ほとんどのエディターで開けるようになったことだろうか. binaryでは当然表示不可能な文字が発生するが, このスクリプトはtar.gzをbase64でエンコードしているから全て表示可能である. ただ, tar.gzのサイズからさらに膨れることにより1ファイルとしての読み込みサイズ限界となってしまう場合はあるだろう.
このスクリプトはテンプレートであり, 実際に利用する場合はファイル終端のbase64にエンコードされたtar.gzを置き換えることとなる. 他のオプション動作は-h
オプションか, そもそもscriptを読んでしまえば察しがつくだろうと思う.