📦

shell script で自己解凍書庫

2022/01/08に公開
2

shell script で自己解凍書庫

結果

いわゆる四角い車輪の再発明だが, gistにてself-extract-script.shを作成した.
-xオプションをつけて実行すると以下のことを行う. なお, このスクリプトはテンプレートであり, 実際の利用する場合はファイル終端のbase64にエンコードされたtar.gzを置き換えることとなる.

  1. 自身の終端のbase64部分のMD5を表示し, 確認を求める.
  • 拒否した場合, 終了する.
  1. 上記を許可した後, 自身の名前のディレクトリを作成する.
  2. 自身の終端のbase64部分をデコードしながら, 作成したディレクトリにtar.gzを展開する.
  3. 展開した根にautorun.shが存在した場合, 実行許可を求める.
  • 拒否した場合, またはautorun.shがない場合は終了する.
  • 許可すると, autorun.shを実行して終了する.

他のオプション動作は-hオプションか, そもそもscriptを読んでしまえば察しがつくだろうと思う.

動機

たまたま見かけた自己追記によるFizzBuzzという記事での終わりの部分に興味を持ったことによる. 以下に引用を示す(2022-01-08).

しかし、シェルがスクリプトを一括ではなく逐次読み込みしかしないという性質は実は重要で、これにより以下のようなスクリプトが動作するようになる。

#!/bin/sh
sed 1,/^exit/d $0 | tar xvzf -
exit $?
(tar+gzipアーカイブをバイナリのままここに貼り付け)

(略)
すなわちシェルによる自己展開アーカイブである。

調べてみれば確かに古くからあるし, 今までも至って当然のように利用していたのだろうと思う. ただ, そうであると認識していなかった. ここで示されているようにどうやらbinaryとして作られることが多いようであるため, 恐らく気にも止めずに実行権限を与えていたのだろう.

しかし, あると知ってしまったなら試す他あるまい. そして, どうせ作るなら(逐次読み込みだからそんなことをする必要はないと述べているのに), shell checkがまぁまぁ通るようにshell側へ寄せて書こうと思った次第である.

結局, 作成時の手間が増えて利便性がさほど上がっていないものが出来上がってしまった. 一応の利点は(多分)ほとんどのエディターで開けるようになったことだろうか. binaryでは当然表示不可能な文字が発生するが, このスクリプトはtar.gzをbase64でエンコードしているから全て表示可能である. ただ, tar.gzのサイズからさらに膨れることにより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工程である. このやり口はシェルスクリプトはバイナリを扱えない。さてどうしよう……パクったものである. なお, そもそも私がPOSIXに偏っているのは, これら記事の影響がとても強いことも認めるけれども, 限定されたLinux環境下で作業をすることがプライベートでも発生するからである. (ポメラDM200上でLinux駆動など)

参考

Discussion

td-shitd-shi

役に立つのはスニペット集や設定ファイルをローカルな手段で人に渡すときとかか?

td-shitd-shi

原理の項を追加. もっとも, scriptを見たほうが早い気がする.