「いざ、鎌倉」もとい「いざ、Ctrl+Z」
こんにちは。お正月からやっているドラクエ8をまだクリアできないkyagiです。・・・どうやったらレティシアに行けるのかわからないままレベル42です。(T_T)
今回は番外編としてシェルスクリプトの話を書きます。
先日のお昼下がりのこと。いつものようにEmacsのtetrisモード(M-x tetris)に熱中していたところ、業務を一生懸命に遂行していたところ、なにやら背後に怪しい人影が2つ 。カムイ伝だとここで「後をとったぞ、カムイ!」と対決シーンになるところですが、ここは「あの青くてちっちゃい星」のRL(Real Life)のお話。後ろにいたのは笑顔がステキでやさしくてかっこよくて、えーとえーと・・・その他いろいろですが理想の上司であるyoishiさんとrkさんの2人。「ちょっとスクリプトを書いてほしいんだけど・・・」とセミナールームに拉致されました。(T_T)
セミナールームでは「以下の3つのファイルを元にして、Asianux/distA/distBのパッケージ比較の表を作成せよ、30分以内でね!」というお題を頂戴しました。なんでも、パッケージ選定会議で使用したいのだ、ということでした。
3つのファイルとはそれぞれ、Asianux_pkg_list.txt/dist_A_list.txt/dist_B_list.txt で
内容は以下のようにそれぞれのディストリビューションに含まれているパッケージ名の一覧になっていました。
Asianux_pkg_list.txt/dist_A_list.txt/dist_B_list.txtの内容
a2ps
acl
acpid
adaptx
adjtimex
agg
aide
alacarte
(...以下、省略...)
ここから以下のような出力の表が欲しいとのこと。
Asianux | distA | distB
packageA | include | not-include
packageB | include | include
packageC | include | not-include
(...以下、省略...)
まずワンライナでロジックを組み立ててみます。比較のベースとなるAsianux_pkg_list.txt から1行読み込んでdist_A_list.txtとの比較を実行して出力を変化させるフィルタを作成してみました。
cat Asianux_pkg_list.txt | while read line ; do echo -n "$line ,"; grep -q "^$line$" dist_A_list.txt; if [ $? == 0 ]; then echo -n "include, "; else echo -n "no, "; fi; done
これで判定のロジックはできたので後は dist_B_list.txt ぶんのコードを追加してやればよいだけになりました。最終的には history | tail > filt.sh したものにcsv形式の出力にする修正を加え以下のようなスクリプトになりました。
#!/bin/sh
cat Asianux_pkg_list.txt |
while read line ; do
echo -n "$line ,";
# Asianux <-> distA
grep -q "^$line$" dist_A_list.txt;
if [ $? == 0 ]; then
echo -n "include, ";
else
echo -n "not-include, ";
fi
# Asianux <-> distB
grep -q "^$line$" dist_B_list.txt
if [ $? == 0 ]; then
echo "include";
else
echo "not-include";
fi
done | column -t
これで一件落着です。今回実感したことは「やはり Ctrl-z は押しにくい」「シェルでもフィルタは結構書ける」ということです。自席に戻って早速キー割り当てを変更したのはいうまでもありません。B-)
追記:
ruby でスクリプトを書き直してみました。機能を少し拡張し、3つのファイルのみならずN個のファイルの比較が可能です。使いかたは以下の通りです。
./Distribtuion2.rb org.txt compare1.txt compare2.txt .... compareN.txt
#!/usr/bin/env ruby
class Distribution
attr_accessor:pkglist
def initialize(file)
@pkglist = Array.new()
File.open(file) do |f|
f.each do |line|
@pkglist.push(line.chomp)
end
end
end
def is_include?(pkg)
if (@pkglist.include?(pkg))
"include"
else
"not-include"
end
end
end
instances = Array.new()
ARGV.each do |ins|
instances.push(Distribution.new(ins))
end
instances[0].pkglist.each do |pkg|
printf("%s ", pkg)
(1 .. (instances.length - 1)).each do |idx|
printf("%s ", instances[idx].is_include?(pkg))
end
print "\n"
end




comm コマンド使っても楽にできますよ。
投稿: jun | 2007年2月 2日 (金) 21:01
junさん、コメントありがとうございます。ひとつずつcommコマンドを使っていくのが一番手っとり早いかったかもしれませんね・・・(汗)。
comm asianux.txt distA.txt
comm asianux.txt distB.txt
でも!引数にいくつ指定してもだいじょうVなように拡張してみましたよ〜!えへへ(<仕事しろ、自分)
投稿: kyagi | 2007年2月 5日 (月) 11:15
ドラクエネタに・・・
レティシアへの行き方って「ひかりの海図」を使うではなかったかな??
違う場所のことだったら・・申し訳ない。
投稿: take0513 | 2007年2月 9日 (金) 20:54
take0513さん、お久しぶりです。情報ありがとうございます。その後、無事いけました。海賊みたいなやつ(キャプテンなんたら)に辿りつくのが一苦労でした。
投稿: kyagi | 2007年2月13日 (火) 10:04
いやいや、無事に行けて何より。
こっちは今はDQMJをやってますよ。
8の時のモンスターなど多数出てくるので懐かしい。
キャプテンクロウもね。
投稿: take0513 | 2007年2月15日 (木) 18:49