[fish] 展開されるalias - abbr


dotfiles Advent Calendar 2019 22日目の記事です。

この記事で触れるdotfilesは https://github.com/wataash/dotfiles の以下のファイルです。

fishの abbr とは

(manual: abbr - manage fish abbreviations)

展開されるalias」です。aliasよりも "fishy" 1 と評され、aliasよりも優れた面があります。

# @yutakatay さんのコメントの通り、zshでも使えるそうです。

gsgit status に展開するabbrを考えてみましょう。以下のコマンドでabbrを登録します:

abbr -a gs git status
# aliasだと
# alias gs='git status'

これで gs という文字列が gs(space) または gs(enter) で展開されるようになります。

展開されるのはargv[0]のみです。コマンド名 (argv[0]) の位置でのみ展開され、引数 (arvg[1..]) では展開されません。

/usr/bin/gs (Ghostscript) を使いたくなったら展開を避けるようにタイプすれば良いです。(command gs でも良いです)

aliasに比べた利点

historyのgreppabilityが上がる

例として git tag を含む履歴を検索してみます。G T Space Ctrl-R

# Ctrl-R にはpecoによる検索を割り当てています(後述)

このように問題なく履歴検索ができていますが、これは alias gt='git tag' だと難しいでしょう。git tag とは関係のない gt を含む履歴が大量にあるからです。(gtest, gtop, libgtk, ...)

また、alias名は変更してしまうと履歴検索の互換性(?)が失われてしまいます。例えば git status のalias gistgst に変更してしまうと、今までの履歴は gist、今後は gst として残るので、両者を同時に検索できなくなります。abbrの場合は両者とも同じ git status として展開されるためこの問題はありません。

引数の削除・変更ができる

例:

abbr -a l  ls -hiFl
# alias l='ls -hiFl'

l
↓ 展開
ls -hiFl
↓ チャットに貼り付けるときは -h -i は削除
ls -Fl

このようにオプションを変更することはaliasにはできません。

視認性が高い

Mozilla rrのチュートリアルをやっているときのことでした。

$ rr record /bin/echo foo
↓ abbr展開
$ rm -rf record /bin/echo foo

あぶねー!!
abbr -a rr rm -rf は1日10回とか使うので絶対忘れないはずなんですが、このときは頭から抜けていました。こわっ 2
aliasだったら気づかずに実行していたかもしれません。(sudo 付いてなかったのでこの場合 /bin/echo はセーフですが。。)

あと他の人に端末操作を見せるときが楽です。aliasを使うと都度説明が必要になっちゃいますよね。あと将来の自分がhistoryを見たときにaliasが理解できなくなっているかもしれない?

abbr tips

abbrを思い出す

abbr | wc -l したら412個ありました。当然忘れます。個人的にやっているabbrの思い出し方を紹介します。

  1. git を含むabbrを探す
    • abbr | pecogit で検索すれば良いです。abbr | peco もよく使うので abp としてabbrしています。
  2. gs で始まるabbrをリスト
    • G S Ctrl-I Ctrl-S V Space
    • Ctrl-ITab と同じ
    • Ctrl-S でSearch
    • abbreViation の V で検索。これだけでほぼabbrに絞れる

読み込まれていないときだけabbr読み込み

私のabbrはすべて読み込むのに1秒くらいかかります。fish起動のたびに読み込むには長すぎます。
ところでabbrの実体はuniversal variableです。
abbr -a gs git status がやっていることは set -U _fish_abbr_gs 'git status' と同じです。(space、enterを押したときの展開は、universal variablesと比較して判定する実装になっています)

これを利用して、gs というabbrが登録されているときだけ = _fish_abbr_gs というユニバーサル変数が登録されているときだけ、abbr一覧を読み込むようにしています。

config.fish
if set -qU _fish_abbr_gs && source ~/.config/fish/config_abbr.fish

ユニバーサル変数なので明示的に消さないとabbrは残り続けます。リロードするには一旦全てのabbrを消してから読み込み直す必要があります。

for a in (abbr --list); abbr --erase $a; end
source ~/.config/fish/config_abbr.fish

これもabbrにしておくと良いでしょう。

abbr -a abe 'for a in (abbr --list); abbr --erase $a; end'
abbr -a abs "source ~/.config/fish/config_abbr.fish"

グローバルalias

fishではzshのグローバルエイリアスは実装しない方針になっています。zshのグローバルaliasでの

alias -g L='| less'
foo L  # -> foo | less

のようなパイプと同じことをfishでやるには bindcommandline を使います (by @GReagle@github):

# by @GReagle@github
# https://github.com/fish-shell/fish-shell/issues/1963#issuecomment-93775067
function bind_global_alias
        switch (commandline -t)
  case "l"
    commandline -rt '| less'
  case "h"
    commandline -rt '| head'
  case "t"
    commandline -rt '| tail'
  case "g"
    commandline -rt '| grep'
  case "w"
    commandline -rt '| wc'
  case "cc"
    commandline -rt '| ccze -A'
  end
end

bind \cx bind_global_alias

これで L Ctrl-X| less に展開されるようになります。

abbr コマンドも commandline を使って実装されているので似たような動作になっています。greppabilityが高いという点もabbrと似ていますね。fish哲学の "The law of orthogonality" を感じます。

pecoによる履歴の絞り込み

私のfishの履歴は10万行近くあります。3

ls -hFl ~/.local/share/fish/fish_history  # 7.1MiB
history wc -l                             # 91660

標準の Ctrl-R で履歴を遡るのはしんどいです。pecooh-my-fish/plugin-pecoを入れておきましょう。4 5

sudo apt install peco
yum install peco  # 未確認
brew intsall -v peco

# go getの場合:
# pecoでは go get は非推奨ですが、多くの人にとって推奨方法の glide install は面倒でしょう…
# 私はgo getで入れてしまっています。
go get -v -u github.com/peco/peco

# https://github.com/jorgebucaran/fisher
curl https://git.io/fisher --create-dirs -sLo ~/.config/fish/functions/fisher.fish

# https://github.com/oh-my-fish/plugin-peco
fisher add oh-my-fish/plugin-peco
config.fish
function fish_user_key_bindings
  bind \cr 'peco_select_history (commandline -b)'
end

コマンドにコメントをつけておく

abbrとは直接関係無いですが、パイプをたくさん使ったシェル芸には long | long | command # summary comment とコメントをつけておくのがオススメです。pecoでコメントを検索できるようになるのと、コメントを読んだだけで何のコマンドか思い出せるようになります。

例:git tagをすべて削除する git tag | xargs git tag -d # delete remove all local tags

まとめ

abbr使いましょう!!!!


  1. fishのデザインに沿っていてイケている、くらいの意味 

  2. abbr -a rr rm -rf は流石にアグレッシブすぎるのでやめました。 

  3. このままだと上限の256Ki行を越えそうだ… 

  4. fzfによる履歴検索は個人的に相性が悪いと感じました。曖昧に検索したい場面があまり無かった。他の方はどうでしょうか? 

  5. oh-my-fish/plugin-peco は oh-my-fish でのインストールが想定されていますが、個人的にomfは推奨しません。omfを入れるとプロンプトに時刻を表示するようになるのですが、ターミナル横幅の計算が間違っていて長いコマンドとかfull-width charactersを打つとぐちゃぐちゃになる。