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でも使えるそうです。
gs を git 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 gist を gst に変更してしまうと、今までの履歴は 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の思い出し方を紹介します。
-
gitを含むabbrを探す
-
abbr | pecoでgitで検索すれば良いです。abbr | pecoもよく使うのでabpとしてabbrしています。
-
gsで始まる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一覧を読み込むようにしています。
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でやるには bind と commandline を使います (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 で履歴を遡るのはしんどいです。pecoとoh-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
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使いましょう!!!!
-
abbr -a rr rm -rfは流石にアグレッシブすぎるのでやめました。 ↩ -
fzfによる履歴検索は個人的に相性が悪いと感じました。曖昧に検索したい場面があまり無かった。他の方はどうでしょうか? ↩
-
oh-my-fish/plugin-peco は oh-my-fish でのインストールが想定されていますが、個人的にomfは推奨しません。omfを入れるとプロンプトに時刻を表示するようになるのですが、ターミナル横幅の計算が間違っていて長いコマンドとかfull-width charactersを打つとぐちゃぐちゃになる。 ↩






