コマンドにタグ付けをして後で検索できるようにするハック

口上

「あれ、先日調べたあのコマンドの名前なんだっけ」
なんて言いながら、google様に検索をかけるなんてことは皆さんもよくあるのではないでしょうか。
しかし、これは当然時間の無駄ですよね。同じ事に何度も時間をかけたりなんてしたくないですし。


こんな時、ちょっとハッカーな人はシェルのヒストリをたっぷり溜めておいて、シェル組み込みのヒストリ検索(ctrl + r とかで呼び出すやつ)などを使って調べたりするかもしれません。ただ、残念ながら自分の場合、コマンド名の断片すら思い出せないことも少なくありません。


こんなわけで、以前よりコマンドにタグ付けとかメモ書きをして、後で検索できるような仕組みが欲しいと考えていたのですが、なかなか実現には至っておりませんでした。
しかし、今日ふと簡単に実現できる方法を思いついたので、本エントリで紹介させて頂こうと思います。

やり方

  • タグ付けやメモ書きをする

コマンド実行と直接関係のない文字列を記録しておくために、ダミーの環境変数を使います。
タグ付けならこんな感じ

$ M=svn,import,repository; svn import hoge_direcotory svn+ssh://svn.bar.jp/home/taro/repos/

メモ書きならこんな感じ

$ M="svn command to import files"; svn import hoge_directory svn+ssh://svn.bar.jp/home/taro/repos/

ちなみに、"M="というのは「メモ」の意です。
「ノート」の意で"N="とかにした方がいいのかも。

  • とりあえず検索してみる

シェル組み込みのヒストリ検索を使って検索ができます

ただこれだと、メモ書きの内容のいくつかを頭から覚えていないと駄目なので、使いにくいですね。

そこで、もう一工夫して、ANDとかORの条件を使って検索をかけられるようにしてみました。

  • もう一工夫 - 下準備 -

必要なスクリプトのセットアップをします。
まず、以下の二つをパスの通ったディレクトリに置きます。


#!/usr/bin/ruby

#ヒストリファイルのパスは適宜変更のこと
history_file = ENV["HOME"] + "/.zsh_history"
command_str = "grep-wrapper \"" + ARGV[0] + "\" " + history_file
str_arr = Array.new()
`#{command_str}`.each_line{ |line|
if line.index(":0;") != nil
str_arr << line.split(":0;")[1]
else
str_arr << line
end
}

str_arr.uniq!()
str_arr.each{ |elem| puts elem }

    • ファイル名:grep-wrapper


#! /bin/sh

if [ $1 = "-h" ]; then
echo "Usage: grep-wrapper "
echo "An example of query-string:"
echo " \"aaaa & bbb | cccc\" means \"aaaa and (bbb or cccc)\""
echo "**You should pay attention about a rule that \"|\" is stronger than \"&\" in this script**"
exit 1
fi

#process parts splited by "&" one by one
file_name=$2
num=1
a_part=`echo "$1" | cut -f $num -d '&'`
greped_str=`cat $2`
while [ $a_part ]
do
num=`expr $num + 1`
greped_str=`echo "$greped_str" | egrep "$a_part"`

#end processing if query string doesn't have "&"
#in other words, query string is composed of a part
echo "$1" | grep "&"
if [ $? -ne 0 ]; then
break 1
fi

a_part=`echo "$1" | cut -f $num -d '&'`
done
echo "$greped_str"

  • もう一工夫 - 検索する -

例えば「あのウェブカメラの画像を表示するツールなんだっけー」という時は、
「ビデオを・・・・見るとか・・・・入力するとかってタグ付けしたかなー」と予想して

というように検索をかけてやれば、目的のコマンド(xawtv)が見つけられます*1
history-searchでは"&"と"|"の結合規則が通常と逆になっているので注意して下さい。


history-searchがやっている事はヒストリファイルに指定した条件でgrepをかけて、重複を取り除いたり、実行日時の情報の部分を取り除いたりという処理です。


まだまだ使いにくいので、今後"M="とかわざわざ入れないでよくしたり、必要なさそうな出力は除外するように改良して行きたいと思います。


あとは、見つけたコマンドをシェルで実行したい場合、現状だとわざわざコピペしないといけないので、zshのヒストリ検索のようにそのまま実行できるようにしたいところですね。

おわりに

思いついたばかりでまだまだ改良の余地があるかと思いますので、皆様のご意見を頂いてより良いものにして行ければと思います。


ご意見だけじゃなく、もっと便利な検索用スクリプトを書いてくれちゃったりしてもいいですよ!

余談 - 日本語も使えるよ -

シェル組み込みのヒストリ検索では、日本語も使えます*2
例えば、このようにメモ書きしておけば

$ M="subversionでファイルをインポートする"; svn import hoge_directory svn+ssh://svn.bar.jp/home/taro/repos/

こんな感じで検索できます。

history-searchも日本語に対応させたい*3ところですね。

*1:余計なものが入っていて見にくいですが

*2:シェルをちゃんと設定していれば

*3:上のスクリプトでは無理みたい