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 と先に打ってしまうことも多いですが。)
