<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
   <channel>
      <title>ウノウラボ Unoh Labs</title>
      <link>http://labs.unoh.net/</link>
      <description>ウノウ株式会社のデモ版サービスやTIPSなどの情報</description>
      <language>ja</language>
      <copyright>Copyright 2008</copyright>
      <lastBuildDate>Thu, 24 Jul 2008 11:56:57 +0900</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/?v=4.1</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

      
      <item>
         <title>daemontoolsでデーモン管理</title>
         <description><![CDATA[Emacsでbackward-charをC-lに割り当てているbokkoです。「指相撲で相手の指に届かないくらい指が短いので一回も勝ったことがないんです。だからそんな短い指でC-bなんて押してたら指が痛いんです」と言ってもなかなか信じてもらえないのですが、そんな私でも(global-set-key "\C-l" 'backward-char)というelispを評価するだけで快適にプログラミングさせてくれるEmacsが大好きです。


と、タイトルと関係ない話はこれくいらいにしておいて、今日はdaemontoolsのお話です。


<h2>daemontools</h2>

daemontoolsは異常終了してしまったデーモンプロセスを再起動してくれたり、ログローテートを肩代わりしてくれたりするなど、デーモンの制御や管理、監視を行うプログラムの集まりです。例えば、以下のようなプログラムが含まれています。

<ul>
<li>supervise</li>
<ul>
<li>デーモンの起動、監視</li>
</ul>
<li>svc</li>
<ul>
<li>superviseによって監視されているデーモンの制御</li>
</ul>
<li>svstat</li>
<ul>
<li>指定したデーモンの状態を出力</li>
</ul>
<li>setuidgid</li>
<ul>
<li>ユーザIDとグループIDを変更</li>
</ul>
<li>multilog</li>
<ul>
<li>デーモンプログラムの出力をロギング</li>
</ul>
</ul>

ほかにもいろいろありますが、詳しくは<a href="http://cr.yp.to/daemontools.html">本家のマニュアル</a>(<a href="http://www.emaillab.org/djb/tools/daemontools/top.html">日本語版</a>)を見るとよいでしょう。

<h2>インストール</h2>

ソースコードが<a href="http://cr.yp.to/daemontools/install.html">こちら</a>で、SRPMが<a href="http://www.qmailtoaster.org/">こちら</a>で配布されています。Linuxディストリビューションによってはapt-getでインストールすることもできますが、その場合は名前がdaemontoolsではなく、svtoolsになっているものがあります(Ubuntuは後者でした)。インストールすると、/commandに各プログラムが配置され、/にserviceというディレクトリが作成されます。daemontoolsでデーモンを管理する場合、この/serviceディレクトリにデーモンの起動スクリプトやログ収集のためのスクリプトを配置します。

<h2>デーモンの登録</h2>

デーモンを登録するには/service以下に登録したいデーモンの起動スクリプトとログ収集のためのスクリプトを配置します。

<pre class="code">
$ mkdir /var/daemon
$ mkdir /var/daemon/log
$ mkdir /var/daemon/log/main
$ chmod 1755 /var/daemon
$ chmod +x /var/daemon/run
$ chmod +x /var/daemon/log/run
$ chown hoge:fuga /var/daemon/log/main
$ ln -s /var/daemon /service
</pre>

<h3>/var/daemon/run</h3>

<pre class="code">
#!/bin/sh
exec 2>&1 # エラー出力を標準出力へ
exec setuidgid hoge /usr/bin/daemon
</pre>

<h3>/var/daemon/log/run</h3>

<pre class="code">
#!/bin/sh
exec 2>&1 # エラー出力を標準出力へ
exec setuidgid hoge multilog t ./main
</pre>

runを実行したプロセス自身をデーモン化しなければいかないので、必ずexecを付けます。また、runで実行するプロセスはフォアグラウンドで起動させなければいけません。

追記:(2008/07/24)

/var/daemon/runの内容が/var/daemon/log/runのものになっており、/var/daemon/runの内容が抜けていたのを修正しました。また、現行のdaemontools-0.76ではstickyビットを立てる必要はありません。ご指摘ありがとうございます。>fumiyasさん

<h2>デーモンの起動制御</h2>

/service以下のデーモンを起動するにはsvscanを使うとよいでしょう。

<pre class="code">
$ sh -c 'svscan /service &'
</pre>

↑を実行すると/serviceディレクトリ以下にあるすべてのデーモンに対してsuperviseによるデーモンの監視が行えます。なんらかの原因でデーモンが終了してしまってもsuperviseが自動的にデーモンを再起動してくれます。ただ、デーモンプログラム自体に問題があって起動できない場合、何度も再起動を試み、ずっとログに起動失敗のメッセージを書き込み続けてしまうので注意しましょう。

OS起動時からdaemontoolsに関連するプログラムを起動しておく場合は、/etc/inittabに以下の記述をしておくとよいでしょう。

<pre class="code">
SV:123456:respawn:/command/svscanboot      
</pre>                                     

<h3>svcでデーモンに命令を発行する</h3>

svcコマンドを使うと指定したデーモンに対して以下のような命令を発行することができます。

<pre class="code">
$ svc -u /service/daemon # 起動
$ svc -d /service/daemon # 一時停止
$ svc -t /service/daemon # 再起動
               ・
               ・
               ・
</pre>

<h3>svstatで状態確認</h3>

svstatを使うと指定したデーモンの状態を確認することができます。

<pre class="code">
$ svsat /service/daemon # 起動中
/service/daemon: up (pid 8131) 3 seconds
$ svsat /service/daemon # 停止中
/service/daemon: down (pid 8131) 57 seconds, normally up
</pre>

ただ、たまにdaemontools側から起動しているように見えているだけの時があるので注意しましょう。詳しくは後述します。

<h2>ロギング</h2>

デーモンプログラムの出力は/var/daemon/log/runで実行しているmultilogによって/var/daemon/log/main以下に保存されます。multilogもdaemontoolsに含まれるツールの一つです。保存されるログはそのままでは見づらいので、同じくdaemontoolsに含まれるtai64nlocalで見やすい形式に変換するのがよいでしょう。

<pre class="code">$ tai64nlocal < /service/daemon/log/main/current</pre>

<h2>デーモンが正常に動作しない場合の対処法</h2>

最後にdaemontoolsを使用していて実際に遭遇した問題を紹介します。

<h3>デーモンがゾンビプロセス化</h3>

なんらかの原因でデーモンが異常終了したり、正常に起動しなかった場合、デーモンプロセスがゾンビ化することがあります。daemontools側から見ると正常に動作しているように見えてしまうので、デーモンが正常に動作しているかpsコマンドなどを使って調べてみましょう。特に、異常終了した後に、そのままでは正常に再起動できないようなプログラムをデーモン化している場合は注意が必要です。

<h3>superviseがエラーを吐く</h3>

<pre class="code">
supervise: fatal: unable to acquire daemon/supervise/lock: temporary failure
</pre>

既に指定したデーモンに対してsupervise(もしくはsvscan)が起動していたり、操作ミスなどによりsupervise(もしくはsvscan)自体が異常終了した場合に上記のエラーメッセージが出ることがあります。
この場合、該当するデーモンに対して起動しているsuperviseを終了し(svscanが起動している場合は先にそっちを終了します)、以下のファイルを削除します。

<pre class="code">
rm /var/daemon/supervise/lock
rm /var/daemon/log/supervise/lock
rm /var/daemon/log/main/lock
</pre>

追記:(2008/07/24)

一部誤解を与える表現がありましたので、修正しました。

修正箇所

<pre class="code">
supervise(もしくはsvscan)自体が異常終了した場合に
↓
操作ミスなどによりsupervise(もしくはsvscan)自体が異常終了した場合に
</pre>

また、lockファイルを削除するよりもいい方法があるようです(コメント
欄参照)。

ご指摘ありがとうございます>fumiyasさん

<h2>フォト蔵におけるdaemontoolsの活用例</h2>

フォト蔵では今年の7月頃からHyperEstraierによる全文検索を導入したのですが、このHyperEstraierに含まれるestmasterというサーバプログラムの管理にdaemontoolsを活用しています。使い方の一つとしては、estmasterの死活監視があります。estmasterが停止してしまうと検索自体ができなくなってしまいますが、停止してしまってもdaemontools側で自動的に再起動してくれるわけです。


フォト蔵でのHyperEstraierの活用例に関しては、また後日紹介する予定です。


<h2>参考ページ</h2>

<ul>
<li><a href="http://www.emaillab.org/djb/daemontools/daemontools-howto.html">daemontools howto</a></li>
<li><a href="http://cr.yp.to/daemontools.html">daemontools</a></li>
<li><a href="http://www.emaillab.org/djb/tools/daemontools/top.html">daemontools日本語訳</a></li>
<li><a href="http://quox.org/tips/server/daemontools.html">Tip COllection - daemontools</a></li>
</ul>]]></description>
         <link>http://labs.unoh.net/2008/07/daemontools.html</link>
         <guid>http://labs.unoh.net/2008/07/daemontools.html</guid>
         <category>Tips</category>
         <pubDate>Thu, 24 Jul 2008 11:56:57 +0900</pubDate>
      </item>
      
      <item>
         <title>パソナテック10周年記念 シリコンバレーツアー(後編)</title>
         <description><![CDATA[こんにちは、naoya です。

<a href="http://labs.unoh.net/2008/07/post_123.html">前編</a>からすこし間が空いてしまいましたが、後編のレポートをお送りします。

<a href="http://photozou.jp/photo/show/784/10911189"><img src="http://art5.photozou.jp/pub/784/784/photo/10911189.jpg" alt="シリコンバレー風景" width="450" height="300" style="border:0" /></a><br /><a href="http://photozou.jp/photo/show/784/10911189">シリコンバレー風景</a> posted by <a href="http://photozou.jp/mypage/top/784">(C)フォト蔵</a>

シリコンバレーツアーの最終日は、<a href="http://www.chikawatanabe.com/">渡辺千賀</a>さんやGoogleやAdobeで活躍されているエンジニア、フリーランスとして活躍されているエンジニアの皆さんによるパネルディスカッションが開催されました。

まず、各自の自己紹介があったのですが、もともと営業職だったり、英文学の専攻だったり、機械工学だったりと、もともとエンジニアとはまったく関係のない職種や専攻だったことに驚きました。

シリコンバレーにきた経緯もさまざまで、単身でシリコンバレーに来たり、交換留学でアメリカに渡ってシリコンバレーに来たり、スタンフォード大学に留学してと、経緯もさまざまでした。

その中で、「自分を肯定してくれない場所にいても無駄」、「自分の環境を変えるために、そこで頑張って環境を変えるか、まったく別の場所に行くか、この二つの選択肢かない」という意見が出たのですが、まったくそのとおりであると同感しました。

また、日本のエンジニア事情について話題が上がったのですが、エンジニアの評価という点ではシリコンバレーにまさる場所はないとのことです。シリコンバレーでは、エンジニアの給料が一番高く、性別や年齢や国籍などその人のプライベートで差別するような風土はまったくないとのことです。ちょうどパネルディスカッションの中でそのことを象徴する出来事がありました。パネルディスカッションの途中で、参加者からパネラーの皆さんの年齢を質問したのですが、その瞬間にパネルラーの皆さんから「その質問をされたのは、初めですね。」と言っていました。まさに、シリコンバレーというかアメリカは年齢や性別などはまったく関係がなく、そのスキルのみが尊重される場所なのだと思いました。ちなみに、企業のインタビュー（面接）でも性別や年齢をレジュメに書く欄はないそうです。

そのあと、GoogleやAdobeについての企業風土について話題に上がりました。Googleではおもに採用面接の内容に話題に上がりました。Googleでは採用を専門にしているリクルーターがたくさんいるそうです。そのリクルーターから声がかかると、さっそくコード面接になるそうです。コード面接では、出された問題に対して今自分がその問題を解くために何を考えているのか説明しながらホワイトボードにコードを書くそうです。面接官は、実際に入社した人が所属するであろうチームの人たちが担当で全員OKと言わないと合格することはないそうです。最終的にはLarry Pageが判断するとのことでした。
面接は何回も行うようです。
Adobeでは、定期的にパフォーマンスが出ていない人を入れ替えるようになっており、5人くらいのチームで開発するとのことです。また、Adobeはまずフルタイムで雇うのではなく、試用期間を設けてその人のスキルを確認してから正式に社員になれるそうです。Adobeは、約3年から4年くらいずっと働いている人が多いそうで、これはかなりシリコンバレーではめずらしいとのことでした。

最後にアメリカでサバイバルする方法として、自分のアイディアを生み出せるかどうか形にできるかどうかが勝負の分かれ道、自分のスキルなどを精一杯アピールする必要がある、といった方法が挙げられていました。後者は、日本人のあまり得意ではないところなので、相当意識しないと難しいとのことでした。


パネルディスカッションのあと、渡辺千賀さんによるセミナーが開催されました。このセミナーでは参加者の質問を受け付ける時間となりました。参加者からは、英語、アメリカの文化、アメリカで働く方法、などさまざまな質問が挙げられました。その中で、アメリカで働く方法としては、ビザの取得がとても大変ということで、前編でも紹介したVMwareで活躍されている吉澤さんの方法が一番の近道であるとのことでした。


こうして、<a href="http://www.pasonatech.co.jp/sv_tour/">パソナテック10周年記念 シリコンバレーツアー</a>は無事終了しました。パソナテックでは、第二回目も開催したいということで、とても楽しみです。

最後に、今回のシリコンバレーツアーのレポートがいくつか上がっていますので紹介しておきたいと思います。

<ul>
<li><a href="http://gihyo.jp/news/report/01/silicon-valley-tour">パソナテック第1回シリコンバレーツアーPhotoレポート(gihyo.jp)</a></li>
<li><a href="http://blog.pasonatech.co.jp/counselor/career_blog/206/7709.html">シリコンバレーツアーで印象に残った３つのこと</a>(あすなろカウンセラーBlogger)</li>
<li><a href="http://blog.pasonatech.co.jp/mitani/199/7706.html">二人で始めた会社が従業員数20万の企業に：ヒューレット・パッカード</a>(世界を巡るFool on the web)</li>
<li><a href="http://blog.livedoor.jp/ld_directors/archives/51063326.html">シリコンバレーで働くということ</a>(livedoorディレクターBlog)</li>
<li><a href="http://www.itmedia.co.jp/news/articles/0807/08/news048.html">高級住宅地のど真ん中　HP発祥のガレージを見てきた</a>(ITmedia)</li>
</ul>]]></description>
         <link>http://labs.unoh.net/2008/07/10.html</link>
         <guid>http://labs.unoh.net/2008/07/10.html</guid>
         <category>レポート</category>
         <pubDate>Sun, 20 Jul 2008 17:18:40 +0900</pubDate>
      </item>
      
      <item>
         <title>シェルスクリプトでプログラミング</title>
         <description><![CDATA[
パワプロよりパワポケが好きなbokkoです。でも最近はPSPで遊んでいます。


今回はシェルスクリプトやコマンドラインでよく使うプログラムとその使用例の紹介です。

<h2>シェルスクリプトでプログラミング</h2>

シェルスクリプトでは既にあるコマンドを組み合わせてプログラムを書きます。しかし、シェルスクリプトは分岐や繰り返しといった制御構造を持ち、関数や変数を扱ったり、四則演算を行うこともできます。

<h3>演算</h3>

シェルスクリプトで演算を行うにはexprを使います。

<strong>add.sh</strong>

<pre class="code">
#!/bin/sh
A=1
B=2
C=`expr ${A} + ${B}`
echo ${C}
</pre>

↑のadd.shを実行すると、

<pre class="code">
$ sh test.sh
3
$
</pre>

と表示されます。↓のようにexprの引数をスペースで区切らず渡してしまうと、単に1+2と表示されてしまいますので、注意しましょう。

<pre class="code">#!/bin/sh
A=1
B=2
C=`expr ${A}+${B}`
echo ${C}
</pre>

<h3>浮動小数演算</h3>

exprでは整数演算しかできません。シェルスクリプトで浮動小数を扱うにはbcコマンドを使います。

<strong>compressibility.sh</strong>

<pre class="code">#!/bin/sh
SRC_SIZE=100
COMPRESSED_SIZE=15
COMPRESSIBILITY=`echo "${SRC_SIZE} / ${COMPRESSED_SIZE}" | bc -l`
echo ${COMPRESSIBILITY}"%"
</pre>

<pre class="code">$ sh compressibility.sh
6.66666666666666666666%
$
</pre>

有効桁数を指定するにはscale変数を使います。

<pre class="code">#!/bin/sh
SRC_SIZE=100
COMPRESSED_SIZE=15
COMPRESSIBILITY=`echo "scale=2;${SRC_SIZE} / ${COMPRESSED_SIZE}" | bc -l `
echo ${COMPRESSIBILITY}"%"
</pre>

<pre class="code">$ sh compressibility.sh
6.66%
$
</pre>

<h3>分岐</h3>

if文の使い方は以下のような感じです。/home/bokko以下にtest.txtが存在していれば、そのファイルが削除されます。

<pre class="code">#!/bin/sh
TEST_FILE=/home/bokko/test.txt
if [ -e ${TEST_FILE} ]
then
    rm ${TEST_FILE}
    echo "removed "${TEST_FILE}
else
    echo ${TEST_FILE}" is not existed."
fi
</pre>

<h3>繰り返し</h3>

繰り返しにはほかの言語でもよく見られるfor文が使用できますが、書き方はif文と同様、少し独特な感じです。

<pre class="code">#!bin/sh
for srcname in `find /home/bokko/programming/c | egrep '.+\.c$'`;do
    case `basename $srcname` in
        a.c | b.c | c.c) ;; # exclude
	*)
	    # C言語のソースファイルに何かする
    esac
done
</pre>

↑のシェルスクリプトを実行すると、/home/bokko/programinng/c以下にあるC言語のソースファイルに対して「# C言語のソースファイルに何かする」の部分に書かれた処理を実行することができます。「#exlude」のコメントアウトがある行はその名の通り、指定したa.c、b.c、c.cを処理の対象から外しています。

<h2>パイプ</h2>

シェルスクリプトでプログラムを書いたり、普通にコマンドラインで作業していると、あるプログラムの出力を別のプログラムへの入力として扱いたいことがあります。このような複数のプログラム間でのデータの橋渡しをするのがパイプです。一見複雑そうな問題でも個々の小さいプログラムをパイプで繋ぐことによって簡単に解くことができる場合があります。


例えば、以下のようなファイルから重複した行を取り除きたいとします(いい加減な例ですみません)。

<strong>bokko.txt</strong>

<pre class="code">bokko
bokkko
bokkkko
bokko
bokkko
bokko
bokko
bokko
bokkko
bokkko
bokkko
bokkko
bokkko
bokko
bokkko
bokko
bokko
bokkkko
bokkko
bokkko
bokko
bokko
bokkkko
bokko
</pre>

これは↓のようにsortとuniqをパイプで繋げるだけでできます。

<pre class="code">$ sort bokko.txt | uniq
bokkkko
bokkko
bokko
$
</pre>

各行がいくつ重複しているか調べるにはuniqの-cオプションを使います。

<pre class="code">$ sort bokko.txt | uniq -c
      3 bokkkko
     10 bokkko
     11 bokko
$
</pre>

非常に簡単な例ではありますが、sortとuniqはテキストデータの集計や解析をする際に非常に役に立ちます。

<h2>sed</h2>

sedはテキストデータを置換するのによく使われるプログラムです。例えば、先程のbokko.txtの全ての行をbokkoに置換してみましょう。

<pre class="code">$ cat bokko.txt | sed -e 's/bok\+o/bokko/g' | uniq
bokko
$
</pre>

という具合に文字列を正規表現を使って簡単に置換することができます。

<h2>awk</h2>

awkはsedと同じようにテキストを置換したり、整形するためのプログラムです。sedに比べると正規表現の機能が少し弱いですが、テキストの整形機能のほかに四則演算、連想配列、などの機能が備わっています。

sortとuniqの例に比べるとやや冗長ですが、以下のようなawkスクリプトを用意して重複行を数えることができます。

<strong>sort_uniq.awk</strong>

<pre class="code">BEGIN {
    cnt["bokko"] = 0;
    cnt["bokkko"] = 0;
    cnt["bokkkko"] = 0;
}
/^bokko$/ {
    cnt["bokko"]++;
}
/^bokkko$/ {
    cnt["bokkko"]++;
}
/^bokkkko$/ {
    cnt["bokkkko"]++;
}
END {
    print "bokko:" cnt["bokko"];
    print "bokkko:" cnt["bokkko"];
    print "bokkkko:" cnt["bokkkko"];
}
</pre>

<pre class="code">$ cat bokko.txt | awk -f sort_uniq.awk
bokko:11
bokkko:10
bokkkko:3
$
</pre>

ほかにも、テキストから必要な部分だけを取り出すといったことも簡単に行える機能があります。

<pre class="code">$ du -b test.txt
101     test.txt
$
</pre>

この出力結果の数字の部分だけ取り出したいなら以下のようにします。

<pre class="code">
$ du -b test.txt | awk '{ print $1 }'  
101
$
</pre>

という具合に出力結果の数字部分だけを取り出すのがいとも簡単に行えます。あまり意味はありませんが、以下のようなことも可能です。

<pre class="code">$ du -b test.txt | awk '{ print $2 }'  
test.txt
$
</pre>

つまり、$1、$2という具合に区切り区切りで文字列を取得できるのです。awkではこの区切りをセパレータと呼び、必要に応じて変更することができます。


<h2>JavaScriptやCSSの縮小結果を表示する</h2>

次はちょっとした応用例を紹介します。

映画生活やフォト蔵ではJavaScriptファイルをjs_min.pyで、また、CSSを自作のPHPスクリプトで縮小化しています。CSSの方は縮小化だけでなく、縮小前のソースファイルの収集処理なども全部PHPで書いているのですが、JavaScriptの方はjs_min.pyをシェルスクリプトから呼び出す形にしています。単に縮小化するのもなんなので、どれくらい縮小化できたのか調べてみようと思い、
縮小率の計算や出力結果のフォーマットもやりました。以下はscriptaculous.jsのslider.jsとcheck.js、prototype.jsに対して縮小化スクリプトで実行した時の出力です。

<pre class="code">$ js_minify.sh slider.js
minified:                               slider.js  10354bytes ->   7631bytes reduction percentage:26.30%
$ js_minify.sh slider.js check.js  prototype.js
minified:                               slider.js  10354bytes ->   7631bytes reduction percentage:26.30%
minified:                                check.js   3364bytes ->   2448bytes reduction percentage:27.23%
minified:                            prototype.js  96653bytes ->  72255bytes reduction percentage:25.24%
$ 
</pre>

↑のスクリプトではJavaScriptの縮小前と縮小後のソースファイルから縮小率を計算してその結果を表示しています。ファイルを縮小化させるのにjs_min.pyを使っていますが、残りはシェルスクリプト、sedやawk、bcなどの既存のプログラムだけで実現しています。

以下がそのシェルスクリプトです。引数を指定しない場合はJS_SRC_DIR以下の全てのJavaScriptファイルを縮小化します。

実際に使う場合はJS_SRC_DIRとJS_MINIFIED_DIRのディレクトリ構成が同じである必要があります。また、ファイルパスの長さやファイルサイズに合わせてprintfのフォーマットを調整するのがよいでしょう。

<pre class="code">#!/bin/sh
HOME_DIR=/home/${USER}/jsdir # 任意のパラメータ
JS_SRC_DIR=${HOME_DIR}/jssrc # 任意のパラメータ
JS_MINIFIED_DIR=${HOME_DIR}/minifiedjs # 任意のパラメータ
JSMIN_DIR=/home/${USER}/bin # 任意のパラメータ
TOTAL_SRC_SIZE=0
TOTAL_MINIFIED_SIZE=0
js_minimize () {
    SRC_PATH=`echo ${JS_SRC_DIR}/$1 | sed -e 's/\.\///g'`
    MINIFIED_PATH=`echo ${JS_MINIFIED_DIR}/$1 | sed -e 's/\.\///g'`
    SRC_SIZE=`du -b ${JS_SRC_DIR}/$1 | awk '{ print $1;}'`
    python ${JSMIN_DIR}/jsmin.py < ${SRC_PATH} > ${MINIFIED_PATH}
    MINIFIED_SIZE=`du -b ${JS_MINIFIED_DIR}/$1 | awk '{ print $1;}'`
    REDUCTION_PERCENTAGE=`echo "(1.0 - ${MINIFIED_SIZE} / ${SRC_SIZE}) * 100" | bc -l`
    REDUCTION_PERCENTAGE=`echo ${REDUCTION_PERCENTAGE} | sed -e 's/^\(-\?\)\./\10./g'`
    echo $1 ${SRC_SIZE} ${MINIFIED_SIZE} ${REDUCTION_PERCENTAGE} | sed -e 's/\.\///g' | awk '{
         printf("minified:%s %dbytes -> %dbytes reduction percentage:%5.2f%%\n", $1, $2, $3, $4);
	 }'
    TOTAL_SRC_SIZE=`expr ${TOTAL_SRC_SIZE} + ${SRC_SIZE}`
    TOTAL_MINIFIED_SIZE=`expr ${TOTAL_MINIFIED_SIZE} + ${MINIFIED_SIZE}`
}
cd ${JS_SRC_DIR}
if [ "$1" != "" ]
then
    while [ "$1" != "" ];do
	if [ -e ${JS_SRC_DIR}/$1 ]
	then
	    js_minimize $1
	else
	    echo ${JS_SRC_DIR}/$1" does not exist."
	fi
	shift 1
    done
else
    for srcname in `find . | egrep '.+\.js$'`;do
	case `basename $srcname` in
            exclude1.js | exclude2.js) ;; # exclude
	    *)
		js_minimize $srcname
	esac
    done
    TOTAL_REDUCTION_PERCENTAGE=`echo "(1.0 - ${TOTAL_MINIFIED_SIZE} / ${TOTAL_SRC_SIZE}) * 100" | bc -l`
    echo ${TOTAL_SRC_SIZE} ${TOTAL_MINIFIED_SIZE} ${TOTAL_REDUCTION_PERCENTAGE} \
	| awk '{ printf("\ntotal     : %dbytes -> %dbytes reduction percentage:%5.2f%%\n", $1, $2, $3); }'
    echo | awk '{ printf("\nAll JavaScript files minified.\n\n"); }'
fi
</pre>

<h3>参考までに</h3>

縮小化スクリプトによってフォト蔵ではCSSを約15%、JavaScriptを約30%縮小化することができました。中にはファイルサイズが半分以下になったものもいくつかあります。

縮小化自体は既存のスクリプトを使えば簡単にできるので、少しでもサイトのパフォーマンスを上げたいと思っているならば、js_min.pyやYUI Compressorの導入を検討してみるといいかもしれません。

<h2>参考文献</h2>

<div class="amazlet-box" style="margin-bottom:0px;"><div class="amazlet-image" style="float:left;"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4774122610/unoh-22/ref=nosim/" name="amazletlink" target="_blank"><img src="http://ecx.images-amazon.com/images/I/518Z01TPCTL._SL160_.jpg" alt="シェルスクリプト基本リファレンス" style="border: none;" /></a></div><div class="amazlet-info" style="float:left;margin-left:15px;line-height:120%"><div class="amazlet-name" style="margin-bottom:10px;line-height:120%"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4774122610/unoh-22/ref=nosim/" name="amazletlink" target="_blank">シェルスクリプト基本リファレンス</a><div class="amazlet-powered-date" style="font-size:7pt;margin-top:5px;font-family:verdana;line-height:120%">posted with <a href="http://www.amazlet.com/browse/ASIN/4774122610/unoh-22/ref=nosim/" title="シェルスクリプト基本リファレンス" target="_blank">amazlet</a> at 08.07.17</div></div><div class="amazlet-detail">山森 丈範 <br />技術評論社 <br />売り上げランキング: 29058<br /></div><div class="amazlet-review" style="margin-top:10px; margin-bottom:10px"><div class="amazlet-review-average" style="margin-bottom:5px">おすすめ度の平均: <img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5.0" /></div><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> シェルスクリプト本が数ある中で、<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> Linux、Unixユーザならば、一度、読んでおきたい本<br /></div><div class="amazlet-link" style="margin-top: 5px"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4774122610/unoh-22/ref=nosim/" name="amazletlink" target="_blank">Amazon.co.jp で詳細を見る</a></div></div><div class="amazlet-footer" style="clear: left"></div></div>


<div class="amazlet-box" style="margin-bottom:0px;"><div class="amazlet-image" style="float:left;"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4900900583/unoh-22/ref=nosim/" name="amazletlink" target="_blank"><img src="http://ecx.images-amazon.com/images/I/51RTWMQVJML._SL160_.jpg" alt="sed&awkプログラミング" style="border: none;" /></a></div><div class="amazlet-info" style="float:left;margin-left:15px;line-height:120%"><div class="amazlet-name" style="margin-bottom:10px;line-height:120%"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4900900583/unoh-22/ref=nosim/" name="amazletlink" target="_blank">sed&awkプログラミング</a><div class="amazlet-powered-date" style="font-size:7pt;margin-top:5px;font-family:verdana;line-height:120%">posted with <a href="http://www.amazlet.com/browse/ASIN/4900900583/unoh-22/ref=nosim/" title="sed&awkプログラミング" target="_blank">amazlet</a> at 08.07.17</div></div><div class="amazlet-detail">デール ドゥラティ アーノルド ロビンス <br />オライリー・ジャパン <br />売り上げランキング: 86344<br /></div><div class="amazlet-review" style="margin-top:10px; margin-bottom:10px"><div class="amazlet-review-average" style="margin-bottom:5px">おすすめ度の平均: <img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-4-5.gif" alt="4.5" /></div><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> ０から書いたことがありません。<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> 正規表現をマスターしましょう<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-4-0.gif" alt="4" /> Sed&awkプログラミング<br /></div><div class="amazlet-link" style="margin-top: 5px"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4900900583/unoh-22/ref=nosim/" name="amazletlink" target="_blank">Amazon.co.jp で詳細を見る</a></div></div><div class="amazlet-footer" style="clear: left"></div></div>
]]></description>
         <link>http://labs.unoh.net/2008/07/post_124.html</link>
         <guid>http://labs.unoh.net/2008/07/post_124.html</guid>
         <category>Tips</category>
         <pubDate>Thu, 17 Jul 2008 15:20:11 +0900</pubDate>
      </item>
      
      <item>
         <title>TCP/IP入門</title>
         <description><![CDATA[尾藤正人(a.k.a BTO)です

このブログを読んでる方にはWebプログラマが多いかと思いますが、Webの仕組みを基礎から理解してプログラムは書いてますでしょうか。
もちろんそんなことは知らなくても抽象化されてるので気にする必要は全然ないのですが、やはりエンジニアとしてはちゃんとどういうものか理解してプログラムを書いた方がよりよいプログラムが書けると思います。

そこで先日の社内勉強会で、TCP/IPについて軽くおさらいしてみました。
かくいう僕もTCP/IPについて勉強したのは7, 8年前だったのでいろいろ復習してたんですが、忘れていたり、実はちゃんと理解できてなかったことがありました。

せっかくなので資料を公開しておきます。
よかったら参考にしていただければと思います。
	 		 				 				 				 				 		 					<object codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" id="doc_28085529942375" name="doc_28085529942375" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" align="middle"	height="500" width="100%">		<param name="movie"	value="http://documents.scribd.com/ScribdViewer.swf?document_id=3750272&access_key=key-23blsoxvf218757dh4m6&page=&version=1&auto_size=true"> 		<param name="quality" value="high"> 		<param name="play" value="true">		<param name="loop" value="true"> 		<param name="scale" value="showall">		<param name="wmode" value="opaque"> 		<param name="devicefont" value="false">		<param name="bgcolor" value="#ffffff"> 		<param name="menu" value="true">		<param name="allowFullScreen" value="true"> 		<param name="allowScriptAccess" value="always"> 		<param name="salign" value="">		<embed src="http://documents.scribd.com/ScribdViewer.swf?document_id=3750272&access_key=key-23blsoxvf218757dh4m6&page=&version=1&auto_size=true" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" play="true" loop="true" scale="showall" wmode="opaque" devicefont="false" bgcolor="#ffffff" name="doc_28085529942375_object" menu="true" allowfullscreen="true" allowscriptaccess="always" salign="" type="application/x-shockwave-flash" align="middle" height="500" width="100%"></embed>	</object><div style="font-size:10px;text-align:center;width:100%"><a href="http://www.scribd.com/doc/3750272/tcpip">tcpip</a> - <a href="http://www.scribd.com/upload">Upload a Document to Scribd</a></div><div style="display:none"> Read this document on Scribd: <a href="http://www.scribd.com/doc/3750272/tcpip">tcpip</a> </div>	

TCP/IPの勉強には<a href="http://www.amazon.co.jp/exec/obidos/ASIN/4274066770/unoh-22/ref=nosim/" name="amazletlink" target="_blank">マスタリングTCP/IP 入門編</a>がおすすめです。

<div class="amazlet-box" style="margin-bottom:0px;"><div class="amazlet-image" style="float:left;"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4274066770/unoh-22/ref=nosim/" name="amazletlink" target="_blank"><img src="http://ecx.images-amazon.com/images/I/416ehyynIYL._SL160_.jpg" alt="マスタリングTCP/IP 入門編 第4版" style="border: none;" /></a></div><div class="amazlet-info" style="float:left;margin-left:15px;line-height:120%"><div class="amazlet-name" style="margin-bottom:10px;line-height:120%"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4274066770/unoh-22/ref=nosim/" name="amazletlink" target="_blank">マスタリングTCP/IP 入門編 第4版</a><div class="amazlet-powered-date" style="font-size:7pt;margin-top:5px;font-family:verdana;line-height:120%">posted with <a href="http://www.amazlet.com/browse/ASIN/4274066770/unoh-22/ref=nosim/" title="マスタリングTCP/IP 入門編 第4版" target="_blank">amazlet</a> at 08.07.15</div></div><div class="amazlet-detail">竹下 隆史 村山 公保 荒井 透 苅田 幸雄 <br />オーム社 <br />売り上げランキング: 1104<br /></div><div class="amazlet-review" style="margin-top:10px; margin-bottom:10px"><div class="amazlet-review-average" style="margin-bottom:5px">おすすめ度の平均: <img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5.0" /></div><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> まとめ方はうまい<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> ネットワークの基礎を学ぶ上での教科書<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-4-0.gif" alt="4" /> 辞書としてはかなり有用<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> 第３版との異同<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> TCP/IPのバイブル<br /></div><div class="amazlet-link" style="margin-top: 5px"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4274066770/unoh-22/ref=nosim/" name="amazletlink" target="_blank">Amazon.co.jp で詳細を見る</a></div></div><div class="amazlet-footer" style="clear: left"></div></div>]]></description>
         <link>http://labs.unoh.net/2008/07/tcpip.html</link>
         <guid>http://labs.unoh.net/2008/07/tcpip.html</guid>
         <category>ネタ</category>
         <pubDate>Tue, 15 Jul 2008 18:58:28 +0900</pubDate>
      </item>
      
      <item>
         <title>脆弱性検知ツールratproxyをCygwin上で動かしてみました</title>
         <description><![CDATA[こんにちは！やまもと＠テスト番長です。<br />
<br />
先日Googleからプロキシ型の脆弱性発見ツール「ratproxy」が公開されました。<br />
これは触らないと！ということでCygwin上で動かしてみました。<br />
<br />
<a href="http://code.google.com/p/ratproxy/">ratproxy<br />
http://code.google.com/p/ratproxy/</a><br /><br />
]]></description>
         <link>http://labs.unoh.net/2008/07/ratproxycygwin.html</link>
         <guid>http://labs.unoh.net/2008/07/ratproxycygwin.html</guid>
         <category>Tips</category>
         <pubDate>Wed, 09 Jul 2008 18:29:50 +0900</pubDate>
      </item>
      
      <item>
         <title>パソナテック10周年記念 シリコンバレーツアー(前編)</title>
         <description><![CDATA[
こんにちは、naoya です。
先日、<a href="http://www.pasonatech.co.jp/">パソナテック10周年記念イベント</a>として開催された<a href="http://www.pasonatech.co.jp/sv_tour/index.jsp">第1回シリコンバレーツアー</a>に参加させていただきました。
今回は、前編と後編の二回にわけて一人のエンジニアからの視点でシリコンバレツアーのレポートしたいと思います。]]></description>
         <link>http://labs.unoh.net/2008/07/post_123.html</link>
         <guid>http://labs.unoh.net/2008/07/post_123.html</guid>
         <category>レポート</category>
         <pubDate>Tue, 08 Jul 2008 13:56:51 +0900</pubDate>
      </item>
      
      <item>
         <title>横に長いコードはどこで改行していますか？</title>
         <description><![CDATA[<p>中村です。</p>
<p>プログラムコードは1行80文字以内で、というルールを多くのプログラマが知っていると思います。以前はプリンタなどの、ハード的な都合があったみたいですね。現在では81文字になってもそれほど困ることはなさそうですが、今でも、ある程度このルールが守られていることが多いのではないでしょうか。</p>
<p>そんな中、メソッド名などの都合上、どうしても長くなってしまうことがあります。そんなとき、みなさんはどこで改行をしていますか？</p>
<p>例えば、次のようなJavaプログラムがあったとします。</p>
<pre class="code"><code>package net.unoh.labs.longlong;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class Client {

    public static void main(String[] args) {
        
        HttpURLConnection urlConnection = null;
        BufferedReader reader = null;
        
        try {
            URL url = new URL("http://clonedoppelganger.net/");
            urlConnection = (HttpURLConnection)url.openConnection();
            urlConnection.connect();
            reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            while (reader.ready()) {
                System.out.println(reader.readLine());
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}</code></pre>
<p>「reader = new BufferedReader...」のところが文字数オーバーです。私が改行するならこのようにします。</p>
<pre class="code"><code>        try {
            URL url = new URL("http://clonedoppelganger.net/");
            urlConnection = (HttpURLConnection)url.openConnection();
            urlConnection.connect();
            reader = new BufferedReader(
                        new InputStreamReader(urlConnection.getInputStream()));
            while (reader.ready()) {
                System.out.println(reader.readLine());
            }
        } catch (MalformedURLException e) {</code></pre>
<p>これの見栄えが良いのか悪いのかは全く不明ですが、大体悩んだ結果こんな感じになります。関係ないですが、このプログラムを実行すると、指定のURL（ここではclonedoppelganger.net）にアクセスしてコンテンツを出力します。</p>
<p>次のJavaScriptコードの場合はどうでしょうか。</p>
<pre class="code"><code>document.getElementsByTagName('body').item(0).innerHTML = ['Hello', 'World'].join('&lt;br /&gt;');</code></pre>
<p>少々意図的ですが、こんなコードも世の中にはあると思います。私が改行するならこのようにします。</p>
<pre class="code"><code>document.getElementsByTagName('body').item(0).innerHTML
        = ['Hello', 'World'].join('&lt;br /&gt;');</code></pre>
<p>演算子の両隣には半角スペースを空けたり、といった他のインデントは大分と自分のなかで確立されてきたのですが、改行の位置は未だに試行錯誤の連続です。ケースバイケースではありますが、何かしら基準があると悩まずに済むのになともんもんしています。</p>
<p>どう改行する？.orgをそろそろ作るべきかなと悩みます。</p>
]]></description>
         <link>http://labs.unoh.net/2008/07/post_122.html</link>
         <guid>http://labs.unoh.net/2008/07/post_122.html</guid>
         <category></category>
         <pubDate>Sat, 05 Jul 2008 00:05:32 +0900</pubDate>
      </item>
      
      <item>
         <title>続・Emacsを自分で拡張するためのTips</title>
         <description><![CDATA[
今年の春頃からトリプルディスプレイで仕事しているbokkoです。なんだか同僚の視線が気になりますが、あえて空気を読まないことにしています。


前に「<a href="http://labs.unoh.net/2008/01/emacstips.html">EmacsLispを自分で拡張する際のTips</a>」という記事を書きましたが、今回はその続きです。

<h3> EmacsLispは難しい？</h3>

EmacsLisp(以下、elisp)は難しいという意見をたまに耳にしますが、elisp自体はそれほど難しいものではありません。ただ、関数名がバラバラでややこしかったり、マニュアルが巨大でどこを見ていいのかわからず、目的のことをするための関数が見つからない、といったようにユーザが難しいと感じるのはelispという言語そのものではなく、環境(OS、ウインドウ、バッファなど)とのインタフェースにあるため、結果的にEmacsLispは難しいと感じてしまうことが多いようです。
実際、elispでプログラミングしていて感じるのはウインドウやバッファなどのオブジェクトを操作するのにどうやったらいいのかわからなくて途方に暮れるというものです。例えば、

<ul>
<li>バッファを切り替えるにはどうすればいいか？</li>
<li>外部プロセスを起動する方法がわからない</li>
<li>find-fileとかみたいに補完入力をしたいんだけどやりかたがわからない</li>
</ul>

というようなものがあります。調べ方やコツがわかってくれば割とすんなりいくことも多いのですが、慣れるまでは苦労すると思います。(僕もそうでした)

<h3>非対話的に引数で指定したファイルを開く</h3>

elispの拡張を書いていると、C-x C-fやM-x find-fileのように対話的にファイルを指定して開くのではなく、プログラム中で引数に指定したパスのファイルを開きたい場合があります。
それで以下のような処理を書いたとします。

<pre class="code">
(find-file-noselect "/home/bokko/test.txt")
</pre>

名前からして↑の処理を実行するとファイルの内容が現在開いているバッファに表示されそうですが、実際にはそうなりません。この処理を実行すると、指定したファイルのバッファオブジェクトが返ってきます。目的のことをやるには今開いているバッファの内容をこのバッファに切り替える必要があります。バッファの切り替えにはswitch-to-buffer関数を使います。

<pre class="code">
(switch-to-buffer (find-file-noselect "/home/bokko/test.txt"))
;; もしくは
(switch-to-buffer (buffer-name (find-file-noselect "/home/bokko/test.txt")))
</pre>

<h3>バッファからファイルに関する情報を取得する</h3>

現在開いているバッファのオブジェクトを取得するにはwindow-buffer関数を使います。

<pre class="code">
(window-buffer)
</pre>

このオブジェクトからファイルの名前を取得するには、

<pre class="code">
(buffer-name (window-buffer))
</pre>

とします。また、フルパスで取得するにはexpand-file-nameを使います。

<pre class="code">
(expand-file-name (buffer-name (window-buffer)))
</pre>

<h3>外部プロセスを起動する</h3>

Emacsでは外部のプロセスを起動させることができます。既にあるシェルスクリプトなどを使いたい場合はstart-processのような関数を使うといいでしょう。映画生活では僕が去年ちょこちょこっと作ったCSSを縮小化するスクリプトを使っているのですが、僕の環境ではこれをEmacsから呼び出せるように↓のelispを読み込んでいます。

<pre class="code">
(defun compress-css ()
  "compress css"
  (interactive)
  (start-process "compress-css"
         "*compress-css*"
         "css-compressor")
  (message "all css file compressed."))
</pre>

最後のcss-compressorが実行ファイル名です。ここではファイル名だけですが、実際にはパスの通った場所に置くかフルパスで指定します。また、この場合、実行結果は*compress-css*というバッファに吐き出されます。

<h3>補完入力をできるようにする</h3>

C-xC-f(find-file)でファイルを開くとき、Emacsでは補完入力ができます。去年ぐらいの頃にこれをどうやってやるのかわからず、結構悩んだ時期があったのですが、実は専用の関数が用意されているため、割と簡単にできます。以下のelispを実行すると、ミニバッファ内で補完入力ができるようになります。

<pre class="code">
(defvar tags-file-list '(
                 ("eigaseikatu" . "/home/bokko/eigaseikatu")
                 ("photozou" . "/home/bokko/photozou")
                 ))
(setq file (completing-read
   "Tags Key: "
   tags-file-list nil t "")) 
</pre>

タブキーを押すと「eigaseikatu」と「photozou」が候補リストに表示されるようになり、入力した方の値がfileという変数に代入されます。<a href="http://labs.unoh.net/2008/01/emacstips.html">前回</a>紹介したvisit-tags-table-key.elではこの補完入力を行っていなかったため、毎回自分で正確に入力する必要がありましたが、今は上記のようにcompleting-readを使って補完入力をするようにしました。

<h3>elispで使う正規表現</h3>

elispで正規表現を扱う際は注意が必要です。というより、elispに限らず、プログラム中の正規表現を別言語に直接持って行く際には注意が必要です。というのもプログラミング言語で正規表現を扱う場合、その言語が正規表現をリテラルとして扱うのか文字列として扱うのか考慮する必要があります。特に文字列の場合はなにかと面倒です。elispでバックスラッシュにマッチさせるには、

<pre class="code">
\\\\
</pre>

と書く必要があります。これはelispでは正規表現が文字列として扱われるので、余分にエスケープ処理が必要となるためです。sedやawk、もしくはPerlなどで正規表現を使ったプログラムを書いたことのある人には奇妙に思うかも知れませんが、elispやJavaのように正規表現をリテラルではなく、文字列として扱う言語ではこのようにエスケープを多用する必要があります。

<h3>デバッグ</h3>

elispのデバッグをする際はedebug-defunを使うのがいいでしょう。printfデバッグみたいなこともできますが、gdbみたいにステップ実行しながらデバッグすることができるので非常に便利です。
edebug-defunを使うには以下のelispを評価します。

(setq debug-on-error t)

あとはデバッグしたい関数の末尾でM-x edebug-defunと実行した後、その関数を実行すると、ステップ実行ができるようになります。スペースキーを押す度にミニバッファにelispの評価結果が表示されるので、実際にどのように動作しているのか把握しやすくなります。

<h3>目当ての関数を探し出す</h3>

先述したようにelispにはものすごくたくさんの関数があり、目的の関数を探し出すのが大変なのですが、実はelispで使える変数や関数はhelp-for-help関数(C-h)を使ってEmacs上で参照できるので、これである程度その大変さを和らげることができます。この関数を使うとUNIXのシステムコールをmanコマンドで調べるのと同じような感覚で関数の使い方について調べることができます。

<h3>ちょっとした応用</h3>

ここからは私が普段使っているelispのプログラムをちょこっと紹介します。

<h3>別のバッファで同じファイルを開く</h3>

プログラムを編集していると、同じファイルを複数のバッファから編集したくなるときがあります。例えば、同じファイル内にBという関数を呼び出しているAという関数があって、その両方を編集する必要があるような状況です。単純に同じファイルを同じバッファで開いてしまっても意味はないので、ウインドウを縦に分割して、2つのバッファに同じファイルの内容を表示してみます。

<pre class="code">
(defun open-same-file ()
  (interactive)
  (let ((same-file (find-file-noselect (buffer-name (window-buffer)))))
    (progn (split-window-horizontally)
    (other-window 1)
    (switch-to-buffer same-file))))
</pre>

↑の関数を実行すると、C-x 3に割り当てられている関数であるsplit-window-horizontallyによってウインドウが縦に分割され、分割してできた新しい方に元々編集していたバッファの内容が表示されます。僕の環境では、以下のようにelscreen上の別のスクリーンで開くようにしています。

<pre class="code">
(defun elscreen-open-same-file ()
  (interactive)
  (let ((same-file (find-file-noselect (buffer-name (window-buffer)))))
    (elscreen-create)
    (switch-to-buffer same-file)))
</pre>

<h3>C言語のヘッダファイルとソースファイルを関連づける</h3>

C言語でプログラムを書く際、関数の宣言と定義を分離するため、ソースファイル(.c)とは別にヘッダファイル(.h)を書くのが一般的です。そのため、ソースファイルとヘッダファイルとの間を行ったり来たリすることがあります。ずっと面倒だと思っていたので、以下のような関数を呼び出すだけで対応するファイルを開けるようにしました。

<pre class="code">
(defun c-open-relational-file (how-open-type)
  (interactive "nOpen-Type: ")
  (defun get-opened-file-name-prefix (file-name)
    (string-match "^\\([^.]+\\)\\.[^.]+$" file-name)
    (match-string 1 file-name))
  (defun get-ext-type (file-name)
    (string-match "\\.\\([^.]+\\)$" file-name)
    (match-string 1 file-name))
  (defun get-opening-file-name (file-name-prefix ext-list)
    (let ((opening-file-name (concat file-name-prefix "." (car ext-list))))
      (cond ((null (car ext-list))             nil)
            ((file-exists-p opening-file-name) opening-file-name)
            (t                                 (get-opening-file-name file-name-prefix
                                                                      (cdr ext-list))))))
  (let* ((ext-map '(
                    ("h" . ("c" "cpp" "cxx"))
                    ("c" . ("h" "s"))
                    ("s" . ("c"))
                    ("cpp" . ("hpp" "h"))
                    ))
         (opened-file-name (buffer-file-name (window-buffer)))
         (opened-file-name-prefix (get-opened-file-name-prefix opened-file-name))
         (opened-file-ext-type (get-ext-type opened-file-name))
         (opening-file-ext-type-list (cdr (assoc opened-file-ext-type ext-map)))
         (opening-file-name (get-opening-file-name opened-file-name-prefix
                                                   opening-file-ext-type-list))
         (opening-file-buffer (find-file-noselect opening-file-name)))
    (cond ((= how-open-type 1) (elscreen-switch-or-create opening-file-buffer))
          ((= how-open-type 2) (progn (split-window-horizontally)
                                      (other-window 1)
                                      (switch-to-buffer opening-file-buffer)))
          (t                   (message "Illegal Type")))))
</pre>

この関数を実行すると、今編集しているファイルがtest.cというファイルの場合、test.hを別のバッファで開くことができます。最初にどう開くのかを数字で指定して、1の場合はelscreenを使って別のバッファで開くようにし、2の場合はウインドウを縦に分割して新しくできたバッファに対応するファイルを読み込みます。また、ソースファイルとヘッダファイルだけでなく、アセンブリコードのファイル(.s)も開けるようにしています(ただし、ヘッダファイルがある場合はそちらを優先します)。
上記のelscreen-switch-or-createは<a href="http://labs.unoh.net/2008/01/emacstips.html">前回</a>紹介したswitch-to-elscreen-createと同じものです。

<h3>elファイルを再帰的にバイトコンパイルする</h3>

elispのプログラムはそのままでもEmacsが読み込むことができますが、バイトコードにコンパイルすることによって高速化することができます。大きな拡張だと、Makefileが用意されていて、(configure→)make→make installでインストールできるようになっているものもありますが、そうでないものも存在するため、たまに以下のelispを使って複数のelファイルを一気にコンパイルしています。

<pre class="code">
(defun my-byte-compile-directory ()
  (interactive)
  (defun byte-compile-directories (dir)
    (if (file-directory-p dir)
        (byte-compile-directory-r (mapcar (function (lambda (f) (concat dir "/" f)))
                                          (directory-files dir)))))
  (defun byte-compile-directory-r (file-list)
    (cond ((null (car file-list))
           nil)
          ((and (file-directory-p (car file-list))
                (not (string-match "/\.\.?$" (car file-list))))
           (byte-compile-directories (car file-list))
           (if (not (null (cdr file-list)))
               (progn
                 (byte-compile-directories (cadr file-list))
                 (byte-compile-directory-r (cdr file-list)))))
          ((string-match "\.el$" (car file-list))
           (progn
             (byte-compile-file (car file-list))
             (byte-compile-directory-r (cdr file-list))))
          (t
           (if (not (null (cdr file-list)))
               (byte-compile-directory-r (cdr file-list))))))
  (byte-compile-directories (replace-regexp-in-string "/$" "" default-directory)))
</pre>

依存関係とかが複雑でないなら、バイトコンパイルしたい拡張のディレクトリに移動して↑の関数を実行するだけで全てのelファイルをバイトコンパイルしてelcファイルを生成することができます。

追記：(2008/7/3 18:20)

my-byte-compile-directory関数にバグがあったので修正しました。バグの内容ですが、再帰的にバイトコンパイルすると書いてあるのにサブディレクトリのelファイルをコンパイルできるようになっていませんでしたorz。上記の修正版ではちゃんとサブディレクトリのelファイルもバイトコンパイルされます。

<h3>参考文献</h3>

<a href="http://www.amazon.co.jp/exec/obidos/ASIN/4906391702/unoh-22/ref=nosim/" name="amazletlink" target="_blank">やさしいEmacs‐Lisp講座</a>
                      
<h3>おまけ</h3>

<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://labs.unoh.net/2008/07/03/3display/CIMG0559_500.png"><img alt="display3.png" src="http://labs.unoh.net/2008/07/03/3display/CIMG0559_500-thumb-500x375.png" width="500" height="375" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span>
  ]]></description>
         <link>http://labs.unoh.net/2008/07/emacstips_1.html</link>
         <guid>http://labs.unoh.net/2008/07/emacstips_1.html</guid>
         <category>Tips</category>
         <pubDate>Thu, 03 Jul 2008 14:26:50 +0900</pubDate>
      </item>
      
      <item>
         <title>Ext JSをUIに使って携帯サイトのシミュレータを作ってみた</title>
         <description><![CDATA[<p>五十川です。</p>

<p>携帯サイトの見栄えをシミュレートするウェブアプリ作りました。と言っても、実際に作ったのはかれこれ半年以上前で、手直ししてから公開しようと思ってたら、結局「guid=ON」を付け足したくらいであとは放置だったので、さすがにいい加減晒そうと。</p>

<p>任意のヘッダでリクエストして、レスポンスの絵文字とか変換してサイトの見栄えを確認するというものですが、これはそもそもExt JSをいじってた頃に、Ext JSでこういうの作ればいい感じになるんじゃね？ということで、丁度2.0がリリースされた頃にデモ用に作ったものなのでした（なので、かれこれ半年以上前）</p>

<p>実機テストの代用になるわけでは、もちろんありませんが、絵文字も含めたマルチキャリアでの見栄えを手軽に確認したいときなどに、わりと便利に使えてたりします。</p>

<h3>スクリーンショット</h3>

<p>機種ごとのプリセットのヘッダグループをYAMLファイルに書いておいて、以下のようにプルダウンメニューから選択して切り替えます。この画面で直接ヘッダの値を書き換えたり、任意のヘッダを追加したりもできます。</p>

<div><a href="http://photozou.jp/photo/show/784/10507746" title="リクエストヘッダ/機種の選択・編集"><img src="http://art2.photozou.jp/pub/784/784/photo/10507746.png" width="450" height="338" alt="リクエストヘッダ/機種の選択・編集" /></a></div>

<p>レスポンスのヘッダとボディ（HTMLソース）を確認できますが、HTMLソースは以下のようにタグなどを色分けして、行番号を付けて表示します。</p>

<div><a href="http://photozou.jp/photo/show/784/10507747" title="レスポンスボディ/HTMLの確認"><img src="http://art7.photozou.jp/pub/784/784/photo/10507747.png" width="450" height="338" alt="レスポンスボディ/HTMLの確認" /></a></div>

<p>アクセス履歴を保存してドメイン別に表示します。ページタイトル、URL、アクセス日時で並べ替えができ、それぞれダブルクリックで、そのページに再度アクセスできます。</p>

<div><a href="http://photozou.jp/photo/show/784/10507330" title="ドメイン別アクセス履歴の表示"><img src="http://art1.photozou.jp/pub/784/784/photo/10507330.png" width="450" height="338" alt="ドメイン別アクセス履歴の表示" /></a></div>

<h3>その他の機能</h3>

<ul>
  <li>QRコード表示します。</li>
  <li>Basic認証をエミュレートします（開発環境には必須かな）</li>
  <li>iモードの「UTN」と「guid=ON」をエミュレートします。リクエストヘッダのUser-Agentに個体識別情報が含まれる場合は、UTN属性のある要素からのリクエストでは個体識別情報を含むUser-Agentを、それ以外は個体識別情報を除去したUser-Agentを送信します。同様に、リクエストURLのクエリーストリングに「guid=ON」が含まれる場合、X-Dcmguidヘッダが設定されてれば送信します。</li>
  <li>iモード以外ではCookieの送受信をエミュレートします。</li>
</ul>

<p>サーバサイドのプログラムは諸般の事情でPHP4スクリプトです（PHP5でも動作確認してます）。PHP4でのHTMLスクレイピングには限度があるので、そのあたりの処理は限定的になってます。</p>

<h3>試してみようと思ったかたは</h3>

<p><del>以下アーカイブをどうぞ。</del></p>

<p><del>mobile-simulator-1.0.tar.gz</del></p>

<p><a href="http://code.google.com/p/japanese-mobile-phone-simulator/">Google Code</a>に移動しました（2008-07-10）</p>

<p>しかしこいつは、各機能を実現するのにさまざまなオープンソースソフトウェアを利用させていただく他力本願なつくりなので、アーカイブの中身だけでは動きません。以下利用させていただいているソフトウェアの一覧です。それぞれ必要な段取りは、アーカイブのREADMEをご覧ください。</p>

<dl>
  <dt><a href="http://extjs.com/products/extjs/">Ext JS 2.x</a></dt>
  <dd>
    <p>2.0と2.1で確認してます。それ以前のバージョンでは動きません。</p>
  </dd>
  <dt><a href="http://php-develop.org/MobilePictogramConverter/">MobilePictogramConverter 絵文字変換ライブラリ</a></dt>
  <dd>
    <p>絵文字の変換表示にはこちらを利用させていただいてます。</p>
  </dd>
  <dt><a href="http://www.swetake.com/qr/qr_cgi.html">QRcode Perl CGI &amp; PHP scripts ver. 0.50</a></dt>
  <dd>
    <p>QRコードの表示にはこちらを利用させていただいてます。</p>
  </dd>
  <dt><a href="http://pear.php.net/package/HTTP_Client">PEAR HTTP_Client</a></dt>
  <dd>
    <p>仮想HTTPクライアントのコアはこちら。</p>
  </dd>
  <dt><a href="http://pear.php.net/package/Text_Highlighter">PEAR Text_Highlighter</a></dt>
  <dd>
    <p>レスポンスボディの強調表示に。</p>
  </dd>
  <dt><a href="http://sourceforge.net/projects/spyc/">spyc 0.3</a></dt>
  <dd>
    <p>YAMLのパースはこちら。</p>
  </dd>
  <dt>Jsphon - JSON in PHP</dt>
  <dd>
    <p>JSONのエンコード/デコードはこちら。</p>
  </dd>
  <dt><a href="http://www.famfamfam.com/lab/icons/silk/">SILK ICONS</a></dt>
  <dd>
    <p>アイコン画像に利用させていただいています。</p>
  </dd>
</dl>
]]></description>
         <link>http://labs.unoh.net/2008/07/ext_jsui.html</link>
         <guid>http://labs.unoh.net/2008/07/ext_jsui.html</guid>
         <category>携帯</category>
         <pubDate>Thu, 03 Jul 2008 03:41:16 +0900</pubDate>
      </item>
      
      <item>
         <title>禁煙しようとしてみました</title>
         <description><![CDATA[<p>yukiです。<br />ウノウでは喫煙者がわりと少なく、自分やごくまれに吸う人間を含めてもせいぜい6人ほどしかいません。世間ではついに来月から関東でもタスポが始まりますし、これを機に禁煙を始めてみようかと思い、色々探してみたところ、よさそうなものが見つかったのでためしにやってみることにしました。</p>

<p><a href="http://www.pfizer.co.jp/pfizer/company/press/2008/2008_04_22_02.html">ファイザー製薬/チャンピックス錠</a></p>

<p>この薬は国内初の「飲む禁煙補助薬」で、従来のニコチンパッチなどとは違い、脳の受容体などに直接効いてくれるそうなので、非常にラクに禁煙できるらしいです。<br />
簡単にまとめると、<br />
	</p><ul><li>健康保険が適用される(一部例外あり)</li><ul><li>3ヶ月間連続して2週間に1度必ず通うこと</li><li>1年に1度だけ<br /></li></ul><li>3ヶ月間、朝晩の食後に1錠ずつ飲むだけ</li><li>飲み始め1週間は喫煙しても良い</li><li>我慢するというよりも、タバコが嫌いになる(まずくなる)</li><li>喫煙しても満足感を得られにくくする<br /></li>
</ul>こんな感じです。健康保険が適用されるとはいえ、基本的に病気ではないので制限が厳しくなっているようです。<br />みなさんもご存知の通り、「禁煙すれば年○○円貯金できるよ！」とか「健康になるよ！」とかよくいいますが、なかなか禁煙できない人(自分)にとっては「ふーん」で終わっていたのですが、割とよさそうなので試してみることにしました。<br />現在服用を始めて5日目ですが、確かにタバコが美味しく感じられなくなってきましたし、本数自体も意識せず自然に減ってきたように思います。<br /><br />仕事中などに煮詰まってくるとついつい気分転換にタバコ休憩しがちですが、基本的に「タバコを吸うとスッキリする」というのは間違いで、「吸っていないとイライラするようになる」のが解消されるだけ、ということらしいですし、何よりも仕事の効率化に相当貢献してくれることだと思います。<br /><br />3ヵ月後、見事に禁煙できていなかったら笑ってやってください。]]></description>
         <link>http://labs.unoh.net/2008/06/post_121.html</link>
         <guid>http://labs.unoh.net/2008/06/post_121.html</guid>
         <category>lifehacks</category>
         <pubDate>Wed, 18 Jun 2008 19:50:05 +0900</pubDate>
      </item>
      
      <item>
         <title>Google Analyticsで特定のリンクのクリック数を調べる</title>
         <description><![CDATA[<p>yamaokaです。</p>

<p>
Webサイトを運営していると、同じページに複数の箇所からリンクが貼られている場合に、特定のリンクからのアクセスがどれぐらいあるかを調べたいことがあります。
</p>

<p>
もちろん、異なるURLで訪問者にアクセスしてもらえばトラッキングできるので、適当なクエリーストリングをリンクのURLに付加すれば調べることができるようになります。
<pre class="code"><code>&lt;a href=&quot;/foo?bar&quot;&gt;baz&lt;/a&gt;</code></pre>
ただし、その場合permalink（固定されたURL）ではなくなってしまいますね。
</p>

<p>
<a href="http://photozou.jp/">写真でつながる共有サイト「フォト蔵」</a>では、アクセス解析に<a href="http://www.google.co.jp/analytics/ja-JP/">Google Analytics</a>を利用しています。Google Analyticsを利用している場合、次のようにして特定のリンクからのアクセスを違う名前で扱うことができるようになります。
<pre class="code"><code>&lt;a href=&quot;/foo&quot; onclick=&quot;pageTracker._trackPageview('/foo?bar')&quot;&gt;baz&lt;/a&gt;</code></pre>
詳細な情報については、Googleによる<a href="http://www.google.com/support/googleanalytics/bin/answer.py?hl=jp&answer=55597">「_trackPageviewとは何ですか。どのような場合に使用しますか。」</a>を参照してください。この方法なら、URLは元の状態のままpermalinkを保つことができます。
</p>

<p>
このリンクからのアクセス数をGoogle Analyticsで調べるには、「/foo?bar」というURLにどれだけアクセスされているかを検索すればOKです。簡単ですね。単純なページ遷移なら「ナビゲーションサマリー」で確認することができますが、特定のリンクをターゲットに調査したい場合にはこの方法が便利です。
</p>

<p>
Google Analyticsは本格的に使おうとするとかなり高機能なので、<a href="http://www.google.com/support/googleanalytics/">ヘルプ</a>を見たりあちこちのページを開いたりして、いろいろ試してみるといいと思います。「セッション」「コンバージョン」など、Google Analyticsで用いられている用語の定義も一度確認しておくことをオススメします。
</p>]]></description>
         <link>http://labs.unoh.net/2008/06/google-analytics-trackpageview.html</link>
         <guid>http://labs.unoh.net/2008/06/google-analytics-trackpageview.html</guid>
         <category>Tips</category>
         <pubDate>Thu, 12 Jun 2008 10:44:02 +0900</pubDate>
      </item>
      
      <item>
         <title>テスト担当者のモチベーション #2</title>
         <description><![CDATA[こんにちは！　やまもと＠テスト番長です。
今年も梅雨の季節になりました。これから毎日じめじめするのかと思うと、どうしてもテンションが下がりがちになりますね。前回モチベーションのお話をしたのですが、その後で良い記事を見つけたのでご紹介したいと思います。

<a href="http://www.stickyminds.com/testandevaluation.asp?ObjectId=13658&Function=DETAILBROWSE&ObjectType=ART&sqry=%2AZ%28SM%29%2AJ%28ARTCOL%29%2AR%28createdate%29%2AK%28topicarea%29%2AA%28SWTST%29%2A&sidx=5&sopp=10&?sid=1&sqry=%2AZ%28SM%29%2AJ%28ARTCOL%29%2AR%28createdate%29%2AK%28topicarea%29%2AA%28SWTST%29%2A&sidx=5&sopp=10">Out of the Rut</a>
By Michael Bolton

テストに飽きてしまったらどうしたらよいか？という問題について筆者の経験から色々とアドバイスをしてくれています。詳細は記事を読んでいただくとして、見出しだけちょっとまとめてみましょう。
<h3>担当箇所を取り替えてみる</h3>
担当箇所を他のメンバーと交換すると、より上手くいくようになるかもしれません。

<h3>変化をつける</h3>
いったん手を止めて、今と違うアプローチの仕方を考えてみましょう。

<h3>他の人々とコミュニケーションする</h3>
プログラマとチャットしたり、ハマる箇所についてユーザーと話したり、他のテスターとペアでテストしてみましょう。リフレッシュできます。

<h3>他の何かに注目する</h3>
一つのことに注目しすぎて煮詰まるのは良くありません。

<h3>自動化する</h3>
単調な繰り返しのタスクはなるべく自動化してしまいましょう。

<h3>費用対効果を考える</h3>
やらなくていい作業だからやる気が出ないのかもしれません。重要でないものにコストをかけるのは、クライアントも望まないでしょう。

<h3>作業を確認する</h3>
自分の作業が有益なものかクライアントやマネージャーと話し合いましょう。

<h3>ちゃんと休憩する</h3>
散歩に出たり、雑誌を読んだり、自転車に乗ったり、コーヒーを飲んだり、お菓子を食べたり、お使いをしたり、シャワーを浴びたりして、気分を変えましょう。


記事の最後に、「テストがつまらないのはそれが上手くいっていないときだけで
重要な情報を探したり、何かを学べているときは面白いものだ」と述べられています。

常に前向きでいられる工夫を忘れないようにしたいものですね。

]]></description>
         <link>http://labs.unoh.net/2008/06/_2.html</link>
         <guid>http://labs.unoh.net/2008/06/_2.html</guid>
         <category>Tips</category>
         <pubDate>Tue, 03 Jun 2008 18:31:40 +0900</pubDate>
      </item>
      
      <item>
         <title>技術系勉強会が楽しくなるかもしれないこと</title>
         <description><![CDATA[Keitaです。

最近、世の中では勉強会に参加される方も多くて僕個人も勉強会に参加させてもらったり、開催のお手伝いをさせてもらうことが多くなりました。
勉強会にもいろいろあって、もはやカンファレンスじゃん？みたいなのもあったりするのですが、個人的には小規模なものが比較的好きです。

そこで、僕が技術系の勉強会に参加するにあたって、よりその勉強会を楽しむために何をしているかをさらしてみようかと思います。

<h3>ノートパソコンを持っていく</h3>
ノートパソコンは技術系勉強会にいくとほとんどの人が持っていっています。
ちょこっと話している内容を試したり、ustで放送したり（ちゃんと許可はとりましょう）いろいろできて便利です。場合よっては電源や、延長コードとかももってくるといいでしょう。


<h3>インターネット接続環境を確保する</h3>
インターネットに接続していたほうが何かと便利です。たとえば、発表中にわからない単語があったりすしたら調べることができます。
発表するときにはネット環境が必要なことがあるかもしれません。
こういうときに、会場で、無線LANなどをお借りすることもできますが、人数が多いときに最大接続数をオーバーしたりトラブルがつき物です。
私は、イーモバイルなどの、安定してつながる環境を用意しています。（というか、家のインターネットへの接続もイーモバイルなんですけど。）

<h3>懇親会に参加する</h3>
懇親会にはぜひ参加しましょう。といっても飲み会の場合が多いのですが、ポロリな情報もあったりしていろいろ面白いです。

<h3>参加者意識をもつ</h3>
カンファレンスならともかく、勉強会なのですから聞き手ではなく参加者として振舞うと、いろいろ得なことがあります。もしあなたが口下手だったり人見知りするタイプだったらむしろ発表するといいと思います。
発表にはスライドというメモがあるわけですから、比較的口下手でもしゃべりやすいです。
そして、もし発表したならば、懇親会や休憩時間に誰かが話しかけてきてくれたりして、可能性が広がります。
直接人に話しかけるより、プレゼン資料を読むだけで自分をアピールできるって考えると、とても気持ちが楽にならないでしょうか。

<h3>試してみる</h3>
勉強会で興味がでていたものを、試してみるのはすごく重要です。
発表者の人の発表がうまい場合に、わかったつもりになってしまうことが多いのですが、発表した内容そのままでもいいので、一回試してみると、明らかに理解度が深まることがあります。

<h3>感謝する</h3>
会場を貸してくれた方に、発表者に、開催した人に、参加した人に感謝していると、なんだかとってもやさしい気持ちになれます。

<h3>レポートとかをブログに書く</h3>
ブログに書くまでが勉強会らしいです。（私はあまり書かないのですがやっぱり書いたほうがいろいろ幸せにはなります。）できれば、行われたことだけじゃなくて感想とかもそこらへんに書いてあると、開催者としては、たとえ悪いことが書いたとしてあっても参考や励みになります。

と、いうわけできれいごとを並べてみましたが、個人的には上のようなことを意識しています。
勉強会によって刺激をうけて技術共有ややる気が出てくれば、きっとあなたの開発効率はあがると思います。

以上、ご参考になれば幸いです。]]></description>
         <link>http://labs.unoh.net/2008/05/post_116.html</link>
         <guid>http://labs.unoh.net/2008/05/post_116.html</guid>
         <category>lifehacks</category>
         <pubDate>Fri, 30 May 2008 12:30:00 +0900</pubDate>
      </item>
      
      <item>
         <title>いまさらコマンドラインの便利さを主張してみる</title>
         <description><![CDATA[尾藤正人(a.k.a BTO)です

僕の偏見かもしれませんが、Webプログラマの方の多くはコマンドラインをうまく活用できてないように感じます。
コマンドラインを使いこなすには最初にある程度の勉強が必要で、その敷居の高さのせいであまり便利さが感じられないのかも。
そこで、今更ながらコマンドラインの便利さを高らかに主張してみます。

<h3>ワイルドカード</h3>

ワイルドカードという特殊文字を使うと特定パターンのファイル名を簡単にしてできます。
これは知ってる人も多いので、詳細は割愛。

ワイルドカードでうまくいかない場合は後述するfindコマンドを使います。

<h3>zshのワイルドカード</h3>

zshのワイルドカードを使うと、ちょっとしたfindコマンドのようなファイル名のマッチができます。
簡単に紹介すると次のようなことができます。

<pre class="code">
echo **/foo # 再帰的に 'foo' にマッチ
echo *(/)    # ディレクトリだけマッチ
echo *(.)    # 標準ファイルだけマッチ
echo *(@)    # シンボリックリンクにだけマッチ
</pre>

<h3>パイプ処理</h3>

僕がコマンドラインが好きな最大の理由がパイプ処理です。
パイプ処理の仕組みは非常に単純で、入力と出力をパイプのようにどんどん加工していくだけです。

<h3>パイプ処理は組み合わせて簡単に複雑なことができる</h3>

パイプ処理を使うと様々なコマンドラインツールを組み合わせて処理することができます。
パイプ処理のおかげで、UNIXのツールは一つ一つが単純な処理だけ行えばよくなり、組み合わせることで複雑な処理がいとも簡単に行えるようになります。

パイプ処理を使って簡単な処理を組み合わせて複雑な処理を実現するのはプログラミングに似てます。
プログラミングも一つ一つの処理は単純ですが、組み合わせることで複雑な処理が実現できます。
違いはパイプ処理の方が早く、短く目的を実現できるところでしょうか。

<h3>パイプ処理の例</h3>

例えば、subversionで新規ファイルを全てaddするとかは、こんな感じでできます。

<pre class="code">
svn status|grep '^?'|awk '{print $2}'|xargs svn add
</pre>

これぐらいの機能ならGUIアプリでも提供されてるでしょうが、例えば画像ファイルだけ追加したい場合はどうでしょうか。
GUIアプリの場合はアプリ自体に機能がなければお手上げですが、コマンドラインならいとも簡単に実現できます。

<pre class="code">
svn status|grep '^?'|grep '¥.gif$'|awk '{print $2}'|xargs svn add
</pre>

<h3>パイプ処理で活用したい文字列処理ツール</h3>

UNIXにはパイプ処理を活用するツールがいろいろあります。
特に、<strong>sed</strong>, <strong>awk</strong>, <strong>perl</strong>, <strong>ruby</strong>のようなパイプ処理で使いやすい文字列処理を提供しているツールを活用するのがいいでしょう。
perlやrubyのような汎用的な言語を一つマスターしておくと、応用範囲が格段に広がります。
個人的にはsed, awkをよく使い、少し複雑な処理にはrubyを使ってます。

<h3>findで対象範囲を絞り込み、xargsで効率よく実行する</h3>

findとxargsを使うとコマンドラインの活用範囲が一気に広がります。
findを使って処理対象のファイルの絞り込みが行え、xargsを使うことでコマンドを効率よく実行することができます。
提供されているコマンドがどんなに単純な処理しか行えなくても、findとxargsを組み合わせることによっていとも簡単に複雑な処理が行えるようになります。

xargsに関してはディノのhnwさんが大変素晴らしい記事書いてくれてるので、そちらを参考していただければと思います。

<a href="http://openlab.dino.co.jp/2008/02/20/133431188.html">いまさらxargsの便利さを主張してみる</a>

<h3>ヒストリ</h3>

コマンドラインを活用する上で、非常に重要なのがヒストリです。
実行したコマンドがどんどんたまっていくヒストリは自分自身の財産です。
ヒストリにたまっているコマンドに素早くアクセスすることで、目的の処理を素早く行うことができるようになります。

ヒストリを使いこなす上で重要なのが、素早く目的のコマンドにアクセスすることです。
僕がよく使ってるヒストリ検索方法を紹介してみます。
使っているシェルはzshです。
zshでしか使えない機能もあるので、この機会にzshに乗り換えてみるのもいいかもしれません。

<h3>Ctrl+r</h3>

インクリメンタルなキーワード検索です。

<h3>Ctrl+p, Ctrl+n</h3>

Ctrl+p でヒストリの一つ前に戻ります。
Ctrl+n でヒストリの一つ次に進みます。
前後に目的のコマンドがあることがわかっている場合に有効です。

<h3>Meta+p, Meta+n</h3>

<strike>zshでしか使えません(たぶん)。</strike>
cshでも使えるようです。
入力したコマンドで始まるヒストリの履歴のみ、Ctrl+p, Ctrl+nと同じようにたどります。
例えば、"mysql" と入力してMeta+p, Meta+nを押すとmysqlで始まるヒストリだけたどれます。

<h3>Ctrl+o</h3>

zshでしか使えません(たぶん)。
Enter(Ctrl+m)の代わりにCtrl+oで実行すると、実行後のプロンプトにヒストリ内の次のコマンドが自動で入力されます。
ヒストリ内の一連のコマンドを実行するときに便利です。
言葉で説明するのが難しいので、実際に使ってみるとわかると思います。

<h3><strike>grep $HOME/.history</strike>history|grep foo</h3>

ヒストリを直接grepします。
乱暴な方法ですが、非常に便利です。

<h3>まとめ</h3>

コマンドラインの便利さが伝わったでしょか(伝わってないかな)。
プログラミングしてない人にプログラムの便利さを伝えるのが難しいように、コマンドラインを使ってない人にコマンドラインの便利さを伝えるのはなかなか難しいのかもしれません。

プログラミングは最初は慣れるまで時間がかかりますが、慣れたら非常に便利です。
コマンドラインもプログラミングと同じで、慣れるまで時間がかかりますが、慣れたら非常に便利です。
コマンドラインもプログラミングと似たようなエッセンスがありますので、ぜひともチャレンジしてみてはいかがでしょうか。]]></description>
         <link>http://labs.unoh.net/2008/05/post_120.html</link>
         <guid>http://labs.unoh.net/2008/05/post_120.html</guid>
         <category></category>
         <pubDate>Wed, 21 May 2008 12:00:41 +0900</pubDate>
      </item>
      
      <item>
         <title>[書評] Database Media</title>
         <description><![CDATA[<a href="http://labs.unoh.net/cgi-bin/mt-search.cgi?tag=gotandajin&blog_id=2">gotandajin</a>です。

今日は書籍「Database Media」の書評、ご紹介をさせて頂きます。

当書籍は5章立ての構成となっており、最後の第5章が弊社代表取締役社長、山田進太郎の執筆となっています。

「Database Media」というタイトルですが、第5章では技術的な仕組みとしてのデータベースについてフォーカスするというより、海外のものを主に昨今注目されているウェブサービスを幅広く紹介(例えばFacebook,Twitterなど、またその他ニッチなものまで)、また、今後のウェブ業界におけるキーワードの1つであろうOpen Socialについて触れ、ウェブ業界に与える影響について考察しています。今、海外のウェブ業界で旬なものについて多く触れているので、その辺りの全体像をざっとおさらいしておくのには丁度よいかもしれません。

ご興味がお有りの方は是非手に取ってみて頂ければと思います。

<div class="amazlet-box" style="margin-bottom:0px;"><div class="amazlet-image" style="float:left;"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4844325329/unoh-22/ref=nosim/" name="amazletlink" target="_blank"><img src="http://ecx.images-amazon.com/images/I/41PI3kDha5L._SL160_.jpg" alt="新・データベースメディア戦略。オープンDBとユーザーの関係が最強のメディアを育てる" style="border: none;" /></a></div><div class="amazlet-info" style="float:left;margin-left:15px;line-height:120%"><div class="amazlet-name" style="margin-bottom:10px;line-height:120%"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4844325329/unoh-22/ref=nosim/" name="amazletlink" target="_blank">新・データベースメディア戦略。オープンDBとユーザーの関係が最強のメディアを育てる</a><div class="amazlet-powered-date" style="font-size:7pt;margin-top:5px;font-family:verdana;line-height:120%">posted with <a href="http://www.amazlet.com/browse/ASIN/4844325329/unoh-22/ref=nosim/" title="新・データベースメディア戦略。オープンDBとユーザーの関係が最強のメディアを育てる" target="_blank">amazlet</a> at 08.05.17</div></div><div class="amazlet-detail">橋本 大也 宇佐美 進典 潮 栄治 佐藤 崇 山田 進太郎 <br />インプレスジャパン <br />売り上げランキング: 3515<br /></div><div class="amazlet-review" style="margin-top:10px; margin-bottom:10px"><div class="amazlet-review-average" style="margin-bottom:5px">おすすめ度の平均: <img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5.0" /></div><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> メディア事業者必読の書<br /></div><div class="amazlet-link" style="margin-top: 5px"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4844325329/unoh-22/ref=nosim/" name="amazletlink" target="_blank">Amazon.co.jp で詳細を見る</a></div></div><div class="amazlet-footer" style="clear: left"></div></div>
]]></description>
         <link>http://labs.unoh.net/2008/05/_database_media.html</link>
         <guid>http://labs.unoh.net/2008/05/_database_media.html</guid>
         <category></category>
         <pubDate>Sat, 17 May 2008 19:58:40 +0900</pubDate>
      </item>
      
   </channel>
</rss>
