ちょっと前に、ssh接続時にローカルのrcファイルをそのまま読み込ませる方法について書いたけど、それと組み合わせられるようにインクリメンタルサーチ用のシェル関数で「boco」というものを作ってみた。これはANSIエスケープコードを利用してプロンプト下に標準入力で受け付けた内容を出力させて選択した内容を標準出力で表示させるシェル関数で、外部コマンドとしてgrepとsort、あとはbashの機能のみで動作するように作成している。 あまりにも受け付けた入力が大きすぎる場合は挙動が重くなるが、10000件くらいなら問題なく処理できるので、historyのインクリメンタルサーチくらいなら利用できる。

単体のファイルとして記述しているので、以下のコマンドでダウンロードできる。

wget https://raw.githubusercontent.com/blacknon/boco/master/sh_function_boco

読み込ませるrcファイルの形式だが、以下のような関数とセットで記述してやる。

boco.bashrc
# bocoでhistoryを検索できるようにする function __boco_history_selection() { case ${OSTYPE} in darwin*) local REVERSE="tail -r" ;; linux*) local REVERSE="tac" ;; esac case $(basename ${SHELL}) in zsh*) local BUFFER=$(history -n 1 | eval $REVERSE | awk '!a[$0]++' | boco) CURSOR=$#BUFFER local TYPE=$(whence -w ${CMD}|cut -d" " -f 2) ;; bash*) # historyにタイムスタンプがついてる場合 # local BUFFER=$(history | sed -r 's/^[ 0-9]+ +[0-9]+ [0-9]{2}:[0-9]{2}:[0-9]{2}//g' | eval $REVERSE | awk '!a[$0]++' | boco) local BUFFER=$(history | sed -r 's/^[ 0-9]+ +[0-9]+ +//g' | eval $REVERSE | awk '!a[$0]++' | boco) declare l=$BUFFER READLINE_LINE="$l" READLINE_POINT=${#l} ;; esac } # Ctrl + Rを__boco_history_selectionに割当て bind -x '"\C-r": __boco_history_selection'

後は、bocoのfunctionファイルと上のファイルの内容をセットでbase64に変換し、それをリモートサーバのbashに読み込ませる。

# (注意1) とりあえず読み込ませるファイルはカレントディレクトリにある前提になってるので、適宜書き換えが必要
# (注意2) 読み込ませるファイルの末尾に空行がないとうまく結合されないので、念の為読み込み時に空行を組み合わせている
ssh -t user@hostname 'bash --rcfile <(echo -e '$(cat ./boco.bashrc <(echo) ./sh_function_boco <(echo)|base64)'|base64 -d)'

実行した結果が以下。 Ctrl + Rを押下すると、historyを検索して選択した内容を実行できてることがわかる(一部で表示が乱れているが)。

ちなみに、リモートのbashに対してrcファイルを読み込ませる機能については自前で作ってるsshクライアントのlsshでも実装しているので、こちらでも似たようなことができる。