Was ist FZF?

Bildnachweis: http://unsplash.stfi.re/search/computer?photo=esCc1qx6TVw

Nachdem ich schon über Vim und Tmux längere Artikel geschrieben habe, will ich jetzt das letzte Mitglied meiner Terminal Dreifaltigkeit vorstellen. FZF.

Letztens beobachtete ich einen Kollegen der mehrere Arbeitsstände zeigen und dafür mehrfach einen Git Branch wechseln musste. Dies war recht zeitraubend zu diesem Zeitpunkt der genaue Branchname und Ticketnummer nicht bekannt war und nur mit stark frequenten Wechseln des Fensters funktionierte. Der innere Kommandozeilenliebhaber in mir schrie leise auf: "Warum nutzt du nicht FZF - damit wären wir schon viel weiter". 1

Also - was ist FZF?

Was ist FZF?

FZF ist ein "command-line" Fuzzy Finder 2 und erlaubt das schnelle Suchen innerhalb der Commandline. Und es ist schnell. Rasend schnell.

asciicast

FZF funktioniert in allen gängigen Shells wie z.B. Bash, ZSH oder Fish 3. Ich benutzte FZF zu 95% innerhalb von Vim. Hierfür gibt es auch ein eigenes Plugin namens FZF.vim vom selben Entwickler, dass viele Konfigurationen bereits integriert hat.

FZF bietet eine Vielzahl von Anwendungsmöglichkeiten. Diese alle aufzuzählen würde ausufern, darum nun meine persönlichen Anwendungsfälle. Mehr Beispiele gibt es im FZF Wiki auf Github.

FZF in der Kommandozeile

Ich nutze FZF sowohl in der Kommandozeile als auch innerhalb von Vim. Die folgenden Aliase sollten in eure Alias Datei - vermutlich ist es die bash_aliases kopiert werden. Das Alias lässt sich natürlich noch anpassen.

Anzumerken ist auch, dass diese Beispiele teilweise für Tmux optimiert sind und zusammen mit fzf-tmux aufgerufen werden. Solltet gerade keine Tmux Session laufen wird aber lediglich der Splitscreen wegfallen und FZF im Vollbild geöffnet. Dies ist aber afaik der einzige Drawback.

Und da man nie Code von irgendwelchen Blogs aus dem Internet kopieren sollte, all diese findet ihr auch im Wiki des FZF Github Repos. Vermutlich sogar aktueller.

Git Branches wechseln

fbr() {
    local branches branch
    branches=$(git branch --all | grep -v HEAD) &&
    branch=$(echo "$branches" |
            fzf-tmux -d $(( 2 + $(wc -l <<< "$branches") )) +m) &&
    git checkout $(echo "$branch" | sed "s/.* //" | sed "s#remotes/4*/##")
}

Das Wechseln in einen Git Branch ist an sich recht trivial und mehr oder weniger nur Tipparbeit. Wer wie ich tippfaul ist, wird dieses Alias lieben. Mit diesem Alias (in meinem Fall fbr) in der bash_aliases werden alle Branches, auch Remote Branches, aufgelistet und mit fuzzy-search durchsuchbar. Der Vorgang dauert so insgesammt nur wenige Sekunden.

asciicast

Git Commit Browser

# fshow - git commit browser (enter for show, ctrl-d for diff, ` toggles sort)
fshow() {
  local out shas sha q k
  while out=$(
      git log --graph --color=always \
          --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" |
      fzf --ansi --multi --no-sort --reverse --query="$q" \
          --print-query --expect=ctrl-d --toggle-sort=\`); do
    q=$(head -1 <<< "$out")
    k=$(head -2 <<< "$out" | tail -1)
    shas=$(sed '1,2d;s/^5*//;/^$/d' <<< "$out" | awk '{print $1}')
    [ -z "$shas" ] && continue
    if [ "$k" = ctrl-d ]; then
      git diff --color=always $shas | less -R
    else
      for sha in $shas; do
        git show --color=always $sha | less -R
      done
    fi
  done
}

Wenn schnell ein Commit gesucht wird, hilft bei mir das fshow Alias. Dieses zeigt alle Commits in einer durchsuchbaren Liste an.

asciicast

Prozesse beenden

# fkill - kill process
fkill() {
  pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}')

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

Reagiert ein Prozess nicht, kann dieser direkt mit einer Pid beendet werden. Aber das raussuchen dieser PID in einer langen Liste von aktiven Prozessen und das anschließende killen kann auch etwas umständlich sein. Mit fkill bekomm ich nun eine mit fuzzy-search filterbare Liste und ein Prozess kann mit einem kräftigen Hieb auf "Enter" direkt beendet werden.

asciicast

FZF innerhalb von Vim

In Vim scheint bei mir FZF besonders hell. An sich ist es kein Problem FZF Scripte selber zu schreiben, da aber nicht jeder ein Vimscript und Kommandozeilen Bash Künstler ist 6 gibt es noch das FZF.vim Plugin. Dies ist im Wesentlichen nur ein Wrapper für FZF, der aber die grundlegensten Funktionen bereits implementiert hat und sehr wahrscheinlich völlig ausreichend ist.

asciicast

Die von mir am häufigsten genutzten Befehle:

  • :Files - Projekt übergreifende Suche. In meinen Fall mit Ag.
  • :Commits - Commitsuche im ganzen Projekt. Ähnlich wie mein fshow Alias.
  • :BCommits - Ähnlich wie :Commits, zeigt aber nur die Commits im aktuellen Buffer an.
  • :GitFiles - Suche in allen Gitfiles. Schneller als eine ":Files" Suche und beachtet auch die .gitignore Datei.
  • :History - Listet die zuletzt geöffneten Dateien auf.
  • :Buffer - Listet alle Buffer auf.
  • :BLines - Ermöglicht eine Fuzzy Search in allen Zeilen des aktuellen Buffers.
  • :Colors - Schnelles Wechseln des Color Schemes :D

TL;DR

FZF ist ein mächtiges vielseitiges Tool, was selbst für nur gelegentliche Arbeiten in einer Kommandozeile sehr geeignet ist.

Achja!

Artikel wie diese sind sehr viel Arbeit und freue mich über jedes Feedback. Sollte euch der Artikel gefallen haben, schreibt per Mail oder auf Twitter und abonniert meinen YouTube Channel! Vorallem Feedback zu dem Video ist sehr willkommen.

  1. Ich habe inzwischen aufgehört anderen Menschen meine Arbeitsweisen und Workflows bei jeder Gelegenheit anzudrehen. Regel #32: Sei kein Smart Ass

  2. Für diejenigen unter euch die mit dem Begriff nichts anfangen können, Mit fuzzy ist das ungefähre Suchen eines Begriffs gemeint. Will ich also eine Datei namens fuzzy-finder suchen, gebe ich einige Buchstaben ein, grob in der Reihenfolge wie sie im Dateinamen auftauchen. Zum Beispiel: fzz, fyfi oder auch - und damit erkläre ich zusätzlich noch den Namen - fzf

  3. Sorry, liebe Hyper User

  4. /

  5. a-z0-9

  6. Mich eingeschlossen. Ich habe sehr großen Respekt vor jedem der aus dem Stegreif einen tar Befehl richtig ausführen kann. Dazu ein relevantes XKCD.