もた日記

くだらないことを真面目にやる

fzf(fuzzy finder)の便利な使い方をREADME, Wikiを読んで学ぶ

fzf

github.com

fzf(fuzzy finder)はコマンドラインであいまい検索ができるツール(類似ツールとしてはpercol, peco, selecta, pick, pmenuなどがある)。ファイル名やコマンド履歴などをインタラクティブに絞り込んでいくことができるので慣れると手放せないツールになる。
今までfzfを履歴検索などで何となく使っていたが、見た目の細かい変更方法やプレビュー機能などを知らなかったのでREADME, Wikiを読んで使い方を調べてみる。

f:id:wonder-wall:20170728132353p:plain


インストール

READMEには複数のインストール方法が書いてあるが今回はgitでインストールする(なおシェルはZshを使う)。macOSのHomebrewやWindowsのChocolately、Vimのプラグインとしてインストールする方法はREADMEを参照。
gitでインストールする場合は下記2つのコマンドを実行する。

$ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
$ ~/.fzf/install

~/.fzf/installを実行すると以下のように3回y/nの質問をされるが特に問題がなければ全部yにすればよい。

Downloading bin/fzf ...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   616    0   616    0     0    624      0 --:--:-- --:--:-- --:--:--   623
100  894k  100  894k    0     0  13905      0  0:01:02  0:01:02 --:--:--  8323
  - Checking fzf executable ... 0.17.0
Do you want to enable fuzzy auto-completion? ([y]/n) y
Do you want to enable key bindings? ([y]/n) y

Generate ~/.fzf.bash ... OK
Generate ~/.fzf.zsh ... OK

Do you want to update your shell configuration files? ([y]/n) y

Update /home/vagrant/.bashrc:
  - [ -f ~/.fzf.bash ] && source ~/.fzf.bash
    + Added

Update /home/vagrant/.zshrc:
  - [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
    + Added

Finished. Restart your shell or reload config file.
   source ~/.bashrc  # bash
   source ~/.zshrc   # zsh

Use uninstall script to remove fzf.

For more information, see: https://github.com/junegunn/fzf

具体的には、オートコンプリートを有効にしたい場合は下記質問に対してyにする。

Do you want to enable fuzzy auto-completion? ([y]/n) y

キーバインドを有効にしたい場合は下記質問に対してyにする。

Do you want to enable key bindings? ([y]/n) y

.zshrcにfzfの起動設定を追加する場合は下記質問に対してyにする。

Do you want to update your shell configuration files? ([y]/n) y

最後の質問をyにすると.zshrcの末尾に下記コードが追加される。

[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh

~/.fzf.zshの中ではオートコンプリート、キーバインドの設定がされておりnにした場合は下記コードがコメントアウトされるようだ。

# Auto-completion
# ---------------
[[ $- == *i* ]] && source "/home/vagrant/.fzf/shell/completion.zsh" 2> /dev/null

# Key bindings
# ------------
source "/home/vagrant/.fzf/shell/key-bindings.zsh"


アップデート

fzfは今も開発を継続しているのでアップデートする場合は下記コマンドを実行する(gitでインストールした場合)。Homebrewなどでインストールした場合のアップデート方法はREADMEを参照。

$ cd ~/.fzf && git pull && ./install


使い方:基本

動作確認

インストールが成功していればfzffzf-tmuxというコマンドが使えるようになっている。

$ fzf --version
0.17.0 (e89eebb)
$ fzf-tmux --version
fzf-tmux (with fzf 0.17.0 (e89eebb))

fzfはメインコマンドでfzf-tmuxfzfをtmuxペインで開くコマンドなので、まずはfzfコマンドを使ってみる。 基本的には標準入力からリストを読み込んで、fzfで絞り込みをして、標準出力するという流れになる。
下記コマンドを実行するとカレントディレクトリ以下のファイル一覧が表示されるので、適当な文字を入力して絞り込んでから、リターンキーを押すとselectedファイルに選択したファイル名が出力される(fzfの便利さはわからない例だけど)。

$ find * -type f | fzf > selected

f:id:wonder-wall:20170728140700p:plain

標準入力がない場合はfzffindコマンドでカレントディレクトリ以下のファイルを読み込む(デフォルトはfindだがFZF_DEFAULT_COMMANDで変更可能)。
下記コマンドを実行するとカレントディレクトリ以下のファイルが表示されるので、絞り込みをしてEnterを押すとそのファイルをvimで開くことができる。

$ vim $(fzf)


絞り込み画面での操作

絞り込み画面でのキー操作は以下のようになっている。また、Ctrl-aCtrl-eなどのEmacsキーバインドも使える。

キー 動作
Ctrl-k または Ctrl-p カーソルを上に移動
Ctrl-j または Ctrl-n カーソルを下に移動
Enter アイテム選択
Ctrl-c または Ctrl-g または ESC 終了
Tab または Shift-Tab 複数アイテム選択(-mのマルチセレクトモード時)


絞り込み画面の表示変更

fzfはデフォルトではフルスクリーンモードで表示するが、オプションで表示の変更をすることができる。
絞り込み画面の高さを変更する場合は--heightを、表示を上から下に変更する場合は--reverseを、上下に枠線を表示する場合は--borderオプションを指定する。

$ vim $(fzf --height 40% --reverse --border)

毎回オプションを指定するのは大変なのでお気に入りのオプションは環境変数FZF_DEFAULT_OPTSに指定しておくとよい。

export FZF_DEFAULT_OPTS='--height 40% --reverse --border'

f:id:wonder-wall:20170728141936p:plain

その他のオプションとしては、入力プロンプトやヘッダ文字列を指定する--prompt, --header、マージンを指定する--margin、ファイル数情報をインライン表示する--inline-infoなどがある。

$ fzf --prompt="P " --header="H" --margin=1,3 --inline-info

f:id:wonder-wall:20171004210953p:plain

絞り込み画面での検索パターン

絞り込み画面での検索パターンは以下のようになっている。fzfはデフォルトでは"extended-search mode"と呼ばれるモードになっており、^music .mp3$ sbtrkt !fireのように検索語をスペース区切りで複数指定できる。

文字 説明
sbrtkt sbrtktの文字がどこかにある文字列(あいまい一致)
^music musicで始まる文字列
.mp3$ .mp3で終わる文字列
'wild wildという並びがある文字列(完全一致)
!fire fireを含まない文字列
!.mp3$ .mp3で終わらない文字列

あいまい一致が嫌な場合はfzf -eオプションを指定すると'を付けなくても完全一致になる。 また|はORの意味なので以下のようにすればgo, rb, pyで終わる文字列に一致する。

go$ | rb$ | py$


キーバインド

インストール時にキーバインドを有効にした場合は下記キーバインドが使えるようになっている。

  • Ctrl-t

カレントディレクトリ以下のファイル、ディレクトリが表示され、選択したファイルをコマンドラインにペーストする。コマンドの変更はFZF_CTRL_T_COMMAND、オプションの変更はFZF_CTRL_T_OPTSで指定する。

  • Ctrl-r

コマンド履歴からあいまい検索ができるのでコマンドを再実行したいときに便利。Ctrl-rをさらに押すと時系列順、関連順のソート切り替えができる。追加のオプションはFZF_CTRL_R_OPTSで指定する。

f:id:wonder-wall:20171004215525p:plain

  • Alt-c

カレントディレクトリ以下のディレクトリが表示され、選択したディレクトリにcdできる。コマンドの変更はFZF_ALT_C_COMMAND、オプションの変更はFZF_ALT_C_OPTSで指定する。

f:id:wonder-wall:20171004220032p:plain

オートコンプリート

インストール時にオートコンプリートを有効にした場合は**を押した後にTabを押すと補完が効くようになっている。例えば以下のようにvim **と入力した後でTabを押すと、カレントディレクトリ以下のファイル、ディレクトリが補完される。

$ vim **<TAB>

f:id:wonder-wall:20171004221956p:plain

COMMAND [DIRECTORY/][FUZZY_PATTERN]**<TAB>というパターンで補完できるので、以下のような使い方ができる。

$ vim ../**<TAB>
$ vim ../fzf**<TAB>
$ vim ~/**<TAB>
$ cd **<TAB>
$ cd ~/github/fzf**<TAB>

補完のトリガーを**から変更したい場合は以下のように設定する。

export FZF_COMPLETION_TRIGGER='~~'

補完用のオプションはFZF_COMPLETION_OPTSで設定する。

export FZF_COMPLETION_OPTS='+c -x'


環境変数

fzfはデフォルトではfindコマンドを使うようになっているが、例えばagコマンドを使うように変更する場合は以下のように設定する。

export FZF_DEFAULT_COMMAND='ag -g ""'

「絞り込み画面の表示変更」で書いたようにデフォルトオプションを指定する場合は以下のように設定する。

export FZF_DEFAULT_OPTS="--reverse --inline-info"


使い方:応用

fzf-tmux

tmuxを使っているならfzf-tmuxを使うことで絞り込み画面をtmuxペインとして表示することができる。

$ fzf-tmux --help
usage: fzf-tmux [-u|-d [HEIGHT[%]]] [-l|-r [WIDTH[%]]] [--] [FZF OPTIONS]

  Layout
    -u [HEIGHT[%]]  Split above (up)
    -d [HEIGHT[%]]  Split below (down)
    -l [WIDTH[%]]   Split left
    -r [WIDTH[%]]   Split right

    (default: -d 50%)

使い方はfzfとしていたところをfzf-tmuxに変更すればよい。fzfで使えるオプションは指定できるようだ。

$ vim $(fzf-tmux --reverse)

f:id:wonder-wall:20171004224546p:plain

デフォルトではペインは下部に表示されるが、表示場所とサイズはオプションで変更は可能。

$ vim $(fzf-tmux -l 20% --reverse)

f:id:wonder-wall:20171004224855p:plain

また、FZF_TMUX=1を設定するとCtrl-rなどで呼び出すときにfzf-tmuxを使うようになる。高さを変更する場合はFZF_TMUX_HEIGHTを設定する。

export FZF_TMUX=1
export FZF_TMUX_HEIGHT=10


オートコンプリート(プロセス、ホスト名、環境変数)

オートコンプリートはコマンドによっては適切な項目を補完できるようになっている。
killコマンドではプロセスを補完できる。マルチセレクトモードなのでTabで複数選択してkillできる。

$ kill -9 <TAB>

f:id:wonder-wall:20171004231547p:plain

ホスト名も補完できる。/etc/hosts, ~/.ssh/configから抽出しているようだ。

$ ssh **<TAB>
$ telnet **<TAB>

環境変数やエイリアスも補完可能。

$ unset **<TAB>
$ export **<TAB>
$ unalias **<TAB>


--ansi, --nth, --with-nthと性能

fzfは高速に動作するのでほとんどのケースで性能は気にならないが、下記オプションを指定すると少し遅くなるのでデフォルトオプションとして指定するのはお薦めしないとのこと。

  • --ansi

ANSIカラーコードを有効にする。

f:id:wonder-wall:20171005214957p:plain

  • --nth

検索対象を指定する。図の例ではカンマ区切りで2番目のみを対象としている。

f:id:wonder-wall:20171005215910p:plain

  • --with-nth

--with-nthは検索対象のみが表示される。

f:id:wonder-wall:20171005215936p:plain

外部プログラム実行

execute, execute-silentを使うと絞り込み画面から抜けることなく外部プログラムを実行することができる。 例えば下記コマンドではF1キーを押すとファイルをlessで閲覧し、Ctrl-yを押すと選択行をクリップボードにコピーして終了する(macOSでpbcopyを使える場合)。execute-silentは画面遷移なしに実行するということらしい。

$ fzf --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort'


プレビューウィンドウ

--previewオプションを指定すると、現在行を引数として外部プロセスを実行し、結果を別ウィンドウに表示することができる。例えば下記コマンドを実行すると現在行のファイルをcatでプレビューする。

$ fzf --preview 'cat {}'

f:id:wonder-wall:20171005211103p:plain

プレビューは外部プロセスが完了したときに表示されるので実際はcatよりはheadの方がよいとのこと。

$ fzf --preview 'head -100 {}'

プレビューウィンドウはANSIカラーをサポートしているので下記ツールなどでシンタックスハイライトできる。

以下のようにツールが存在しない場合は別ツールで実行するという制御もできる(図はCodeRayを使用)。

$ fzf --preview '[[ $(file --mime {}) =~ binary ]] &&
                 echo {} is a binary file ||
                 (highlight -O ansi -l {} ||
                  coderay {} ||
                  rougify {} ||
                  cat {}) 2> /dev/null | head -500'

f:id:wonder-wall:20171005211703p:plain

プレビューウィンドウの位置とサイズはオプションで指定可能。

$ fzf --preview 'file {}' --preview-window down:1

f:id:wonder-wall:20171005212156p:plain

色変更

色変更についてはこのページに書いてある。--color=[BASE_SCHEME][,COLOR:ANSI]という形式で色を指定すればよい。

$ fzf --color=bg+:24
$ fzf --color=light,fg:232,bg:255,bg+:116,info:27

常に色を変更したい場合はFZF_DEFAULT_OPTSで指定する。

export FZF_DEFAULT_OPTS='
  --color fg:124,bg:16,hl:202,fg+:214,bg+:52,hl+:231
  --color info:52,prompt:196,spinner:208,pointer:196,marker:208
'

f:id:wonder-wall:20171005210309p:plain

Wikiに書いてあった使用例

Wikiに色々な使用例が書いてあったので便利そうなものを見ていく。

プレビューにツリー表示

Alt-cでディレクトリツリーを表示する例。

export FZF_ALT_C_OPTS="--preview 'tree -C {} | head -200'"

f:id:wonder-wall:20171005225441p:plain

--select-1, --exit-0

--select-1を指定すると選択候補が1つしかないときに自動で選択する。--exit-0を指定すると選択候補がないときに自動で終了する。これらのオプションはFZF_ALT_C_OPTSで有用とのこと。

export FZF_ALT_C_OPTS="--select-1 --exit-0"


フルコマンドプレビュー

コマンドが長すぎて画面に収まらないときに?を押すとプレビューウィンドウにコマンドを表示する。

export FZF_CTRL_R_OPTS="--preview 'echo {}' --preview-window down:3:hidden:wrap --bind '?:toggle-preview'"


fe, fkill

下記コードを.zshrcに記述すると、選択したファイルをデフォルトエディタで開くfeコマンド、選択したプロセスをkillするfkillコマンドが使えるようになる。
このようなコマンド例はExamplesに色々と書いてある。

fe() {
  local files
  IFS=$'\n' files=($(fzf-tmux --query="$1" --multi --select-1 --exit-0))
  [[ -n "$files" ]] && ${EDITOR:-vim} "${files[@]}"
}
fkill() {
  local pid
  pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}')

  if [ "x$pid" != "x" ]
  then
    echo $pid | xargs kill -${1:-9}
  fi
}

Vim連携

fzfの作者によるfzf.vimの使い方は下記記事を参照。

wonderwall.hatenablog.com