fc2ブログ

bashでgit comまでタイプしてタブキーを打つとcommitと補完される謎を追う

ひっそりぃはUbuntu Linux 13.04を使っているのですが、git commitしようとして、何気なくgit comまでタイプしCtrl-i(タブキー)を押すと、なんとcommitと補完され驚きました。

シェルはbashを使っているので、コマンド名やディレクトリ名が補完されるのは当然なのですが、コマンドの引数まで補完されるとは。

bashにこんな機能あったっけ?
と気になったので調べてみた。

調査にはプロセスのsystem callやsignalをtraceできるstraceコマンドを使います。全てのtraceを追うと大変そうなので、補完のためのデータベースを読みに行くのでは?とあたりをつけ、open()のみ追うことにします。

コマンドは、以下の様になります。

$ strace -e open bash


bashが起動する過程でのopen()結果がずらずらと表示され、以下の状態で止まりました。

: (省略)
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
open("/etc/bash_completion.d/zeitgeist-daemon", O_RDONLY|O_LARGEFILE) = 3
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
open("/home/hissorii/.bash_history", O_RDONLY|O_LARGEFILE) = 3
open("/home/hissorii/.bash_history", O_RDONLY|O_LARGEFILE) = 3
open("/lib/terminfo/s/screen", O_RDONLY|O_LARGEFILE) = 3
open("/etc/inputrc", O_RDONLY|O_LARGEFILE) = 3
hissorii@ubuntu:~$


ここで、キーボードにて「git com」までタイプし、おもむろにタブキーをたたくと、

hissorii@ubuntu:~$ git comopen("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
open("/usr/share/bash-completion/completions/git", O_RDONLY|O_LARGEFILE) = 3
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
--- SIGCHLD (Child exited) @ 0 (0) ---
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
open("/dev/null", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
--- SIGCHLD (Child exited) @ 0 (0) ---
--- SIGCHLD (Child exited) @ 0 (0) ---
--- SIGCHLD (Child exited) @ 0 (0) ---
--- SIGCHLD (Child exited) @ 0 (0) ---
mit

と結果が返ってきます。
一行目は「git com」のタイプの直後にopen() traceが被っていますが、気になるものが2行目に見えています。
なにやら /usr/share/bash-completion/completions/git というファイルをオープンしています。

ここでstraceを終了し、このファイルが何者なのか調べてみます。

hissorii@ubuntu:~$ file /usr/share/bash-completion/completions/git
/usr/share/bash-completion/completions/git: UTF-8 Unicode text
hissorii@ubuntu:~$

ふむ、バイナリファイルではなさそうなので中身を見てみると、シェルスクリプトでした。

さらに近辺のファイルを眺めてみると、

hissorii@ubuntu:~$ ls -F /usr/share/bash-completion/
bash_completion completions/ helpers/
hissorii@ubuntu:~$

/usr/share/bash-completion/bash_completion が親玉のシェルスクリプトですね。
改めてbashを起動したときのstrace結果を見てみると、確かにこのスクリプトをopen()していました。

open("/usr/share/bash-completion/bash_completion", O_RDONLY|O_LARGEFILE) = 3


次にcompletionsディレクトリですが、量が多いのでgで始まるものの一部だけを見てみるとこんな感じ。
これらが各コマンドの引数補完をするスクリプト群ですね。

hissorii@ubuntu:~$ ls /usr/share/bash-completion/completions/ | grep ^g | head -15
g++
g4
g77
gcc
gcj
gcl
gdb
gdbus
genaliases
gendiff
genisoimage
getent
git
gitk
gkrellm
hissorii@ubuntu:~$


bash_completionスクリプトとgitスクリプトがそれぞれどのパッケージに属するかを見てみると、

hissorii@ubuntu:~$ dpkg -S /usr/share/bash-completion/bash_completion
bash-completion: /usr/share/bash-completion/bash_completion
hissorii@ubuntu:~$ dpkg -S /usr/share/bash-completion/completions/git
git: /usr/share/bash-completion/completions/git
hissorii@ubuntu:~$

となるので、bash-completionパッケージがbashでのコマンド引数の補完を行う大元のパッケージですね。

各コマンド、例えばgitパッケージの作成者がcompletionsディレクトリに置くスクリプトを提供することでgitコマンドの引数補完ができるようになる訳です。
逆に言うと、completionsディレクトリにスクリプトを提供していないコマンドについては引数補完ができない、ということになります。

改めて、bash-completionというパッケージがbashでのコマンド引数補完の犯人?ということが分かったので、ちょっとググってみました。

以下がオフィシャルサイトのようです。
http://bash-completion.alioth.debian.org/

単なるコマンドの引数補完だけではなく、たとえばsshで接続先ホスト名の補完などもできるようです。
/etc/hostsや~/.ssh/known_hostsを参照したりするのかな?

Copyrightを見ると2008年には既に存在していたようです。全く知りませんでした。
知らず知らずのうちに使っていたかもしれません。
感謝感謝。


Comment

コメントの投稿


管理者にだけ表示を許可する

Trackback

http://hissorii.blog45.fc2.com/tb.php/231-3376c15e

«  | HOME |  »

プロフィール

ひっそりぃ

Author:ひっそりぃ
Twitter:@hissorii_com
GitHub:hissorii


月別アーカイブ


最新記事


カテゴリ



最新コメント


最新トラックバック




RSSリンクの表示


Amazon


QRコード

QRコード

Amazon


ブログランキング

ブログランキング【くつろぐ】
にほんブログ村 ゲームブログ×PlayNCBlogへ

メールフォーム

名前:
メール:
件名:
本文:


カウンタ