Zshにはsuffix aliasやauto cdと呼ばれる機能があります。
suffix aliasは指定の拡張子をコマンドラインにいきなり書くと、 指定のコマンドで開いてくれると言う機能、 auto cdはディレクトリをいきなり書くとそのディレクトリに移動してくれる機能です。
この機能をBashで実現してみました。
Zshのsuffix alias/auto cd
Zshでは
alias -s txt='vim'
としておくとtest.txt
があるディレクトリで
$ test.txt
とtxt
拡張子がついた名前を直接コマンドラインで打つと
$ vim test.txt
としたのと同じように扱ってくれます。
複数ファイルも
alias -s {md,markdown,txt}='vim'
等として指定可能。
またこの様にして指定したファイルに対しては 実行ファイルでなくてもtabによる補完も効く様になります。
また
setopt auto_cd
としておくと、tmp
というディレクトリがある場所で
$ tmp
とするだけでtmp
ディレクトリへ移動できます。
こちらはディレクトリなのでZshでディレクトリも最初から補完される様になっていれば補完が効きます。
Bashでの実装
Bash 4の場合
Bash 4にはZshのauto_cd
に当たる機能がshopt
にあって、
shopt -s autocd
としておけば
$ tmp
cd tmp
と言って移動してくれます。 補完に関しては、Bashでは他にコマンドの候補がない時にはディレクトリが補完されるので、 それと同様の補完は効きます。
suffix aliasの機能を実現するためには、Bash4から実装されてる
command_not_found_handle
という関数を使います。
command_not_found_handle
が設定されていると、
打ち込んだコマンドが間違ってたりして
$ test.md
bash: test.md: command not found
みたいに出る様な状況の時、代わりにこの関数を実行する様になります。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
こんな感じのcommand_not_found_handle
を.bashrcなんかに書いておくと、
$ test.md
とするだけで
$ vi test.md
と同じ事になります。
また、もし該当ファイルが存在しない場合は
通常の出力通りcommand not found
と言って127
(command not foundで通常返す値)を返す様にしています。
注意として、環境によっては
command_not_found_handle
が既に実装されている環境もあります
1。
その機能の恩恵を受けていなければ上書きしてしまっても構いませんが、
もし使ってる場合はcommand_not_found_handle
が定義されてない時だけ
こんな感じで定義するとか
1 2 3 4 5 |
|
元のをキープしたいなら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
こんな感じにしてあげればよいかと思います2。
Bash 3の場合
もしBash 3を使ってる場合はcommand_not_found_handle
を
設定してもコマンドが見つからなくても実行してくれません。
またautocd
もshopt
の中にありません。
この場合、どうしても使いたい場合はPROMPT_COMMAND
にフックを入れて
無理やり実装することが出来ます。
追記: 2017/04/28
このやり方では$cmd
に何も入ってないので
開けません。
最後に使ったコマンドを取ってくる方法としては
history
を使えば無理やり取ってくることは出来ますが、
強引な感じになるので取り敢えずはBash 3では無しで(もうほとんど出会うことも無いですし。)
追記ここまで
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
こんな感じでまずPROMPT_COMMAND
内で一番最初に実行される
関数をcommand_not_found_hook
として実装します(混ざるとあれなのでhandle
関数とは名前を替えておきます)。
PROMPT_COMMAND
では一番最初のコマンドでは$?
に
実際に使ったコマンドの返り値が入ってるので
これを使ってis a directory
やcommand not found
な126
, 127
の場合に色々出来る様にします。
(PROMPT_COMMAND
の中で先に他のコマンドが実行されると$?
にその
結果が入ってしまうので一番最初に行う必要があります。)
その後、直前のコマンドをhistory
で取ってきてそれがファイルである場合には
拡張子をチェックして指定の物で開くようにしています。
ただし、この場合はvi
で開いて終了後、
コマンド自体の終了ステータスは126
なり127
ままになります。
(PROMPT_COMMAND
の中では実際のコマンドのステータスは変更できない)
ちょっとキモチワルイものが残りますがこれで一応
suffix alias的な事はできます。
Bash 3, 4 両方用
Bash 3, 4両方共通の.bashrcを使う場合には
こんな感じでBASH_VERSINFO
の値を使って切り替えを行えばOK。
追記: 2017/04/28
Bash3用のものは削除。
追記ここまで
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
|
ここでは全て適当な編集しそうな拡張子をvi
で開く様にしてるだけですが、
必要なら他にも色々追加できます。
補完
上の実装でZshのsuffix alias的な事をBashで大体出来る様になりますが、 1つ上手く行かないのが補完です。
無理やり補完関数を書けば出来ないことも無いかも知れませんが 最初のコマンド補完を変更する方法がよくわからなかったので取り敢えずそのままに。
シェルの確認
それからBash3が入ってる環境で後からBash4を/usr/local/bin/bash等に
入れてる場合、きちんとログインシェルが変更されてるか
$SHELL
等を見て確認してみてください。
コマンドラインからbash --version
としても
その時使うコマンドとしてのbash
とログインシェルが違う事があるので、
bash --version
としてversion 4.X.XX
と出ても
今いるシェルが3.Xの場合があります。
linux - command_not_found_handler not working in mac - Stack Overflow
この中ではMacでHomebrewを使ってBashを入れて、bash --version
とかで確認しても
ちゃんと4.3.30なのにcommand_not_found_handle
が使えない、
と言っていますが、
上に書いたようにログインシェルを変更してないんだと思います。
(実際自分でも同じような状態になったことがあったので念のため。。。)
まとめ
使えるようになったら便利かな、と思って設定して暫く使ってみましたが、
やはり補完が効かないのが圧倒的に使えないので普通にvi ...<Tab>
と打ってしまいます。
(そしてそっちのが速い。)
ただ、GNU screen上でファイル名をコピーしてパッと開いたりするのはたまに便利だったりはします。
(その場合もまだ慣れてないのでvi
と先に打ってしまうことも多いですが。)