diff, patch, ikill-3.0


GNOME というネットワークと統合された立派なデスクトップ環境があるにもかかわらず, わしがzsh の最新やら設定に血道をあげているのは, はっきりいって, GUI よりも shell の方が便利だからです. shell は速いです. 電光の如くマシンが反応します.

shell はそれだけでも十分便利ですが, shell から呼び出して使う, 小さくてかわいらしいけれど やることだけはしっかりやるというプログラムを組合せることで, UNIX 以外のシステムなら, 血圧を倍くらいに高めながらいちいち全部手でやる か, ソレ用のプログラムを書かないといけない場合でも, UNIX ならコマンド一発で用事が済んじゃったりするのである. もちろん, Linux でもね.

そういうはなしは, 一度 シェル入門 とかいう記事で書いた. これは, その補足だ.

2つのファイルが同じ内容かどうかを調べるという仕事が, けっこうあるはずだ. そんなとき, どうするか? ls -l でサイズを見る? 確かに, サイズが違っていれば, 同じファイルとは言えないな. しかし, 言うまでもなくこの判断は間違う可能性がある. もう一つのファイルが, きっちり同じ数の空白文字で埋め尽くされているかもし れないからね.

比較的よく使われるのは, md5 checksum だ. 悪意あるファイルの改変も, このチェックを逃れる事はできない. 違うファイルは, 絶対に違う checksum を生成するのだ. IP のパケット検査も, これで行われている. ヘッダにパケットの checksum が書いてあり, パケットの checksum を計算して, ヘッダの値と比較することで, パケットが壊れのを調べることができる. (ただし, 改鼠を防ぐことはできない. ) md5 の使い方は,

yuji@aya:~%md5sum /etc/passwd
44b0a137e7d9f176776b11cb6a473c79  /etc/passwd

こんな感じである. md5 アルゴリズムは一方向 hash 関数とか言われるもので, checksum から元のファイルを復元することはできない. だからといって /etc/passwd はねえだろ, つう気もするが.

残念ながら, md5 の checksum を憶えておけるほどの記憶力が俺には無いので, 2つのファイルの checksum を取ったとしても, それを比較するという段階で, 難儀な思いを味わうことになる. まあ, 記憶力が抜群の人であっても, checksum を憶えるのに使うのは止めた方 が良いね. それならタウンページを最初から暗記していった方が, まだしも 役に立つだろうよ. hoge.tar.gz が正式なものかどうかを調べるのには, md5 は役に立つが, ファイルの比較ということになると, イマイチだね.

unix には diff という伝統のコマンドがある. ファイルを比較するという, そのものズバリのコマンドだ. diff は 2つのファイルを行ごとに比較して, 違いがあれば報告してくれる.

これは, 吟味された単純なものをうまく組み合わせることで, どれほどの力を発揮できるようになるか, という好例だ. たとえばあなたが, あるプログラムのバグを見付けて直したとしよう. 直したソースコードをそのまま開発者に送り付けるとどうなるだろう?

まず, 送る必要があるのは修正箇所だけだから, ネットワーク資源の無駄使いに なることだろう. 開発者はそれを全部読まないといけないので, 彼の貴重な労力は開発ではなく ユーザからのメッセージを解読する事に使われてしまう. それに, ちょっと時間が経つと, どこをどう直したかも忘れてしまうものだ.

差分を取ればいい. そんなときに diff である. 差分を取るオプションは -u だ. -r オプションで, ディレクトリ丸ごと差分を取ってくれるぞ.

その差分を統合するコマンドが patch だ. 「パッチを当てる」って奴だ. つまり,

diff -uNr old_dir new_dir | gzip -c > patch.gz

こうやって差分をとり,

zcat patch.gz | patch 

こうやって統合するのである. 文書の校正なんかにも, もってこいの 機能だと思いませんか? 他にもいろんな使い方が考えられる. /etc の下の差分バックアップとかね. diff も patch も詳しい info があるので, それを見てくれ. diff は行指向のプログラムなので, バイナリの差分までは取ってくれん. これはどうやったら解決できるかな? base64(例: mewencode ) か uuencode を使えばなんとかなるが, 差分の方が元のファイルよりもでかくなるかも(uuencode は元ファイルよりも 1.5倍のサイズになる)ね.

バイナリファイルを比較するのは, cmp である. これは, 何バイト目で違っているかをチェックしてくれる. od して diff してもいいけど, バイナリはたいてい 違うかどうかだけが問題だから, cmp で間に合うでしょう.

そういや, 自分のシステムで最大のファイルが何か知ってますか? ディスクが逼迫している人は, 次のコマンドを試してみて下さい.

ls -lR / | sort -n +4

bash なら(もちろん zsh も), パイプの前に " 2>/dev/null" を入れとけば ゴミを見なくて済む.

ikill-3.0

ikill-3.0 をリリース. 幾つかオプションがついた. リクエストがあった job control は, シェルスクリプトが 親のシェルから job の制御情報を取得する方法が判んない(判んないっす. 申し訳ない. でも, 違うシェルだから, 無理? わからんー) ので, 代わりにユーザのプロセスだけを取って来るというオプションを作る. あと, 表示順序を逆転するオプションも付けた. オプションはちゃんと "--" でエスケープできます.

しかし, 今回の改良は, 実はそういうセコいオプションではないのだ. 動作中に検索パターンを入力しなおせるんだーぜー.(コマンドは "a" ) これで, アレもコレも死なせたいというときに, いちいち違う名前を入力して起動しなおさなくてもいいんだーぜー. さらに, プロセスが全部無くなったら次のパターンを入れたりとかもできるんだ. 表示順序もトグルで逆転できるんだーぜー. (コマンドは "r") これで,いちいちリストの最後まで "n" でたどり着かなくてもいいんだーぜー.

プログラミングの課題で, 動かないソース提出してたわりには, 俺ってやるじゃん. もちろん, 以前使えた機能で, 無くなったものは一切無い. (はず.) ええかげんな quote の使い方をだいぶ直したので, ちょっと速くなってもいる. だから, アップグレード必須なのじゃ! これで, パターンの入力プロンプトで, 補完入力とかできりゃ完璧なんだがな. ズギャ.