それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

bash-completion を自分で作る。独自補完を作ってみた。

bash-completion is 便利。

bash-completion って便利ですよね。zsh ユーザには興味のない話かもしれないけど、、zsh に比べ bash はどこでも使えるので便利なんですよね。

brew install bash-completion

また、各コマンドのcompletion もbrew や apt で一緒に入ってくれる。

最近だと、インストールすれば使えるようになっていてナニも考えなくてもイイようになってる。

自分で作ったコマンドはどうするか?

自分で作ったコマンドにも補完機能欲しいじゃん?となると自分で補完も定義することになる。zsh はこの辺たしか自動処理してくれたと思うんだけどね。

自分で作るのめんどくさい?→結構簡単

ぱぱっと読んだだけで、自分で補完機能が簡単に定義できることが分かった。

早速作ってみることに

とりあえず、独自コマンドの代わりに、bash で関数を定義し、関数の引数を補完するようにしてみる。

ステップ1:補完リストを定義して補完する

手順はこんな感じ

  • 関数作って(実験用)
  • 補完関数作って
  • 補完関数をロードして
  • 補完関数を試す。

関数と補完関数を作る

completion_test.sh
### 引数をecho するだけの簡単な関数。
function folder() {
  echo $@
}

### 補完関数。
_folders(){

  COMPREPLY=( takuya hatenablog hello completion )
}
### 補完関数と関数の関連付け
complete -F _folders folder

関数をロード

takuya@~/temp$ source completion_test.sh

使ってみる

takuya@~/temp$ folder

takuya@~/temp$ folder <TAB>
takuya hatenablog hello  world

おおおおお、補完された

ステップ2:補完リストを動的にしてみる。

このままだと、詰まらないし。いつでも固定の補完しか出来ない。

補完関数の中でコマンドをCallして補完の内容がその時の最新のフォルダ一覧になるようにしてみる。

補完関数の候補の改良

とりあえず、ls の結果を補完に表示してみよう。

### 補完関数。
_folders(){
  COMPREPLY=( $(  ls ~ ) )
}

このように書いて source コマンドで関数をリロードする。

実際に使ってみると。。。

実際にコマンド補完を実行してみる。すると$HOMEの内容がズラズラと出てくるようになる。

takuya@~/temp$ folder
Applications  Documents     Dropbox       Movies        Pictures      Sites         temp
Desktop       Downloads     Library       Music         Public        repos         work

これで、補完っぽくなってきた。

ステップ3:入力途中で絞込

ここ迄で補完候補が出るようになったけれど、まだ補完とは言い切れない。

それは入力途中の文字で絞込ができないから。

takuya@~/temp$ folder Do<TAB>
Applications  Documents     Dropbox       Movies        Pictures      Sites         temp
Desktop       Downloads     Library       Music         Public        repos         work

Do と打ち込んでも全てのリストが出力されてしまう。これは不便だ。これでは補完とは到底言い難い。

入力中の文字で絞込処理を書く

### 補完関数。
_folders(){
  COMPREPLY=( $(compgen -W "$(ls ~)" ${COMP_WORDS[COMP_CWORD]}  ) ) 
}

compgen -W で絞込した結果を候補に出るようにする。この時に入力途中の文字は 変数から取得する。

これで補完処理になる。

takuya@~/temp$ folder D<TAB>
Desktop    Documents  Downloads  Dropbox

これで補完処理になる。

出来たコマンドの置き場所

bash-completion は /etc/bash-completion.d/ に保存すれば、自動的にロードされるようになっている。

それは、bash-completion ば .bashrc で読み込まれるように記述されているため

bashrc

bashrc 中に次のような記述がある。

   if [ -f /etc/bash_completion ]; then
      . /etc/bash_completion
   fi

ちなみに homebrew 環境下の場合は次のようになっている。

  brew_prefix=`brew --prefix`
  # enable programmable completion features (you don't need to enable
  # this, if it's already enabled in /etc/bash.bashrc and /etc/profile
  # sources /etc/bash.bashrc).
  if [ -f ${brew_prefix}/etc/bash_completion ]; then
    source ${brew_prefix}/etc/bash_completion
  fi

さらに/etc/bash-completion/ には、次のように記述されており

# source user completion file
[[ $BASH_COMPLETION != ~/.bash_completion && -r ~/.bash_completion ]] \
    && . ~/.bash_completion
unset -f have
unset UNAME USERLAND have

ということで、自作のbash補完関数の保管場所は次の通り。

~/.bash_completion ## 個人用
/etc/bash-completion.d/ ## システム用

に置けば大丈夫。

もちろん、.bashrc に直接書いても問題ないんだけどね。

サブコマンド。

git add ファイル名
git commit -m "コミットログ"

のようにサブコマンドを取るものも、Completionでは定義可能。なのだが、自作コマンドの補完でソコまですることは殆ど無いので。サブコマンドについては参考資料にURLを貼っておくことにする。

自分でちょっと便利に使うためのコマンドでサブコマンドも作りこむことはまぁ少ないよな。

参考資料

bash-completionで独自の補完関数を作成する方法(gistyのサブコマンドを補完するやつ書いてみた) - 今日もスミマセン。