Ubuntuには「command-not-found」というパッケージが最初からインストールされています。ユーザーが入力したコマンドが存在しない場合、必要となりそうなパッケージを推測・提案してくれるニクイアイツです。今回はその仕組みとカスタマイズ方法を紹介しましょう。
command-not-foundの仕組み
UbuntuでCLIで操作している時、およそ人生においてコマンド入力を間違えたことのないパーフェクトヒューマンでもない限り、以下のようなメッセージに遭遇したことがあるでしょう。
これは「command-not-found」というパッケージが提供する機能です。Ubuntuのリポジトリには多種多様なソフトウェアが存在しますが、そのすべてがローカルシステムにインストールされているわけではありません。特に初期のUbuntuは「インストールイメージをCD一枚のサイズに収める」という制約を設けていたため、最初からインストールされているパッケージは限られていました。しかしながら実行しようとしているコマンドとそのパッケージ名が即座にわかるユーザーはそこまで多くありません。そんなユーザーのために、入力したコマンドが見つからなかったときに、可能性のあるパッケージをリストアップしてくれるのがcommand-not-found機能です。
command-not-foundはUbuntu 6.10ぐらいにパッケージが用意され、Ubuntu 7.04から標準でインストールされるようになった、Ubuntuの中ではとても歴史の古いツールです[1]。オリジナルの作者はCanonicalのZygmunt KrynickiとMichael Vogtであり、その実体はPythonスクリプトとなっています[2]。
仕組みはすごく単純です。Bashには検索パスにコマンドが見つからない場合、command_not_found_handle
関数を呼び出すという仕組みが存在します。Ubuntuのbashパッケージが提供する/etc/bash.bashrc
には最初から、command-not-found
がインストール済みならcommand_not_found_handle
を定義するスクリプトが組み込まれていますので、ユーザーが特に設定せずともcommand-not-foundを使えるようになっているのです[3]。
command-not-foundの実体は/usr/lib/command-not-found
です。ここにコマンド引数の最初の文字列(つまりはユーザーが入力したコマンドだと思われる文字列)を渡します。そして次のような流れでメッセージを表示します。
PATH
にはないもののインストール済みかをチェックする
- apt/aptitudeがインストールされていない場合は、ただ「見つかりません」のエラーのみを表示する
- ブラックリスト(後述)に見つかったら、ただ「見つかりません」のエラーのみを表示する
- パス名から該当するパッケージを検索する
- パッケージが複数見つかったらパッケージリストとインストール方法を表示する
- 該当するパッケージが1つのときはインストール方法(
sudo apt PACKAGE
)を提示する
- 該当パッケージのコンポーネント(mainやuniverse)が無効化されていたら有効化するように伝える
- パッケージが見つからずなおかつコマンドが3文字以上なら単なるスペルミスの可能性を考慮して「もしかして」を表示する
つまり「間違え方」によって結構表示の仕方が変わるのです。ちなみにadminグループに加入していたらsudoを使ったインストール方法が提示されますが、加入していない場合は次のようなメッセージになります。
動作をカスタマイズする
command-not-foundは初心者にとって便利な機能ですが、ユーザーによっては「うざったい」と感じるツールでもあります。そこでいくつかのカスタマイズ方法も紹介しましょう。
command-not-foundを無効化する
無効化する一番手っ取り早い方法は、command-not-foundパッケージを削除することです。もしシステム全体としては残しておいて、特定のユーザーだけ無効化したいのであれば「~/.bashrc
」に以下のスクリプトを追加しましょう。
要するに関数の定義を上書きしているだけですね。
オプション付きで実行する
command-not-foundにはいくつかのオプションがあります。「無効化する」と同じような方法で「~/.bashrc
」上で関数を上書きすることで、任意のオプションを指定できます。
使えるオプションは次のとおりです。
- 「
--data-dir
」:データディレクトリを「/usr/share/command-not-found
」に変更します。
- 「
--ignore-installed
」:インストール済みかどうかのチェックを行いません。
- 「
--no-failure-msg
」:候補が見つからなかったときは何も表示しません。
データディレクトリはパッケージ名とコマンド名のデータベースを格納しているディレクトリです。データベースはcommand-not-found-dataパッケージが提供します。独自のデータベースを使いたい場合などに使用します。
「インストール済みかどうかのチェック」は少し説明が必要かもしれません。たとえば「/sbin/parted
」がインストール済みの環境でなおかつ環境変数PATH
に/sbin
が含まれていない場合を考えます。bash的には「parted
」は見つからない状態になるのですが、command-not-foundは環境変数PATH
だけでなく「一般的なコマンドパス」も検索しているため/sbin/parted
コマンドを見つけられます。これが「インストールされているが見つからないコマンド」です。
command-not-foundはこのようなコマンドを「インストール済み」として扱いそのフルパスを提示します。しかしながら、PATH
で見つからない場合は存在しないものとしてパッケージを提案してほしい場合もあるかもしれません。「--ignore-installed
」はそんな用途に適したオプションです。
候補が1つだったらインストールするか問い合わせる
候補が1つだった場合、対象のパッケージをインストールしてくれると、表示されるメッセージをコピー&ペーストする手間が省けます。環境変数COMMAND_NOT_FOUND_INSTALL_PROMPT
に適当な値をセットしておくと、そのような動作になります。
何も入力せずにエンターを押した時はインストールしないようになっていますので安心ですね。
特定のコマンドはデータベース問い合わせさせない
「よく打ち間違えるコマンド」ってありませんか?
「grep」が「grpe」に「git」が「gti」になっていたり、「ls」のつもりが「rm」って打っていたり、「vi」って打つつもりが「emacs」って打ってしまったり……。
いわゆる「手グセ」に起因するものから、キーボードが原因だったり、睡眠不足が原因だったりと打ち間違える理由は様々です。また頻繁に打ち間違えるものに対して、毎回「まだインストールされていません」とか言われるとイラッときますよね。いや、自業自得なんですが。
「~/.command-not-found.blacklist
」に「よく打ち間違えるコマンド」をいくつか入れておくと、command-not-foundはそれを無視してくれます。
データベースへの問い合わせをしなくなるだけで、command-not-foundコマンドは起動するので少ししか応答性はあがりませんが[4]、それでもそれなりに気持ちが楽になることでしょう。
Ubuntu 18.04 LTSでの変更点
このcommand-not-found、ここ数回のUbuntuリリースにおいてはデータベースファイルの更新しか行っていませんでした。つまりコードはほぼそのままでした。修正されたとしてもPython3への対応とか、apt-getからaptへの変更など、周囲の環境にあわせた微調整にとどまっていたのです。
しかしながらUbuntu 18.04 LTSの開発期間では、何がどうなったのか活発にコミットが行われます[5]。1リリース1コミットぐらいの頻度だったのが、ここ半年で60コミット以上、当社比60倍です!
- snapパッケージのコマンドのサポート
- snapパッケージとDebianパッケージの両方の候補があればバージョンも表示
- データベースをGNU dbmからSQLiteへ移行
- リポジトリ上のコマンドメタデータからデータベースを構築(未実装?)
- pyflakes/autopkgtestなどによるコードチェックやテストの実装
- 数千文字渡したときにシステムが固まる問題の修正(LP: #1605732)
- より読みやすくなるよう表示内容の調整
- Python2のサポート終了
おそらくユーザー側が最も恩恵を受けるのが、snapの対応とSQLiteへの移行でしょう。特にSQLiteになることで、低スペック環境下でのcommand-not-foundの「待ち」がだいぶ減ったように感じます。
コマンドメタデータからのデータベース構築は、「sudo apt update
」時をトリガーとしてリポジトリ上のデータからデータベースを再構築する仕組みです。ただしまだリポジトリ側が対応していないようにも見えますので、おそらく将来を見据えた実装なのでしょう。
このようにcommand-not-foundは18.04で大きく変わる予定です。これを機に、今一度手元のツールを見なおしてみてはいかがでしょうか。