Mit Fzf und Fzy die Shell um eine Fuzzy-Suche erweitern

Aus LinuxUser 03/2022

Mit Fzf und Fzy die Shell um eine Fuzzy-Suche erweitern

© Tanawat Pontchour / 123RF.com

Knapp daneben

Fuzzy Finder suchen aus Datenströmen selbst dann Passendes heraus, wenn es keine exakten Treffer gibt.

Die unscharfe Suche gehört heute als fester Bestandteil zum IT-Alltag. Sie korrigiert Tippfehler, spürt Ähnlichkeiten auf und bietet eine Möglichkeit, selbst in unstrukturierten Daten noch mit vertretbarem Aufwand das Gewünschte zu finden. Das Grundprinzip basiert auf der in der 1960er-Jahren definierten Levenshtein-Distanz [1], den sogenannten Wortabständen (siehe Kasten “Levenshtein”). Quasi von Beginn an erweiterten und optimierten Entwickler diesen Algorithmus.

Levenshtein

Die Levenshtein-Distanz beschreibt die minimale Anzahl von Änderungen (Ersetzen, Löschen, Einfügen), die man benötigt, um eine Zeichenkette in eine andere zu überführen. Die gewichtete Anzahl dieser Aktionen bestimmt, wie stark sich die beiden Strings ähneln. Gewichtung bedeutet dabei, dass etwa zwei vertauschte Buchstaben (wie bei einem Tippfehler) weniger ins Gewicht fallen als etwa das Einfügen zusätzlicher Zeichen. Allerdings bringt der Ansatz auch Probleme mit sich: Die Gewichtung hängt von der konkreten Aufgabenstellung (Rechtschreibprüfung, Suche, etc.) und der Sprache ab. So verhalten sich im Deutschen die Begriffe “Wortabstände” und “Wortabstand” zwar inhaltlich sehr ähnlich, weisen aber eine relativ große Levenshtein-Distanz auf.

Allerdings ignorieren bis heute viele Standardwerkzeuge unscharfe Suchen oder beschränken sich auf stark vereinfachte Varianten. So verarbeitet das Tool Grep aus den Coreutils zwar beliebig komplexe reguläre Ausdrücke (Muster), eine unscharfe Suche unterstützt es aber nicht. Für eine solche stehen auf der Kommandozeile neben Agrep [2] und Ugrep [3] noch einige andere, weniger bekannte Tools bereit. Agrep sticht dabei mit einer Best-Match-Option heraus.

Fzf [4] und Fzy [5] (siehe Kasten “Kleiner Bruder”) bereichern den Shell-Baukasten um zwei neue, leistungsfähige Werkzeuge. Sie arbeiten als interaktive Filter, erhalten ihre Daten also voreingestellt auf der Standardeingabe und liefern die Ergebnisse auch dort wieder aus. Interaktiv bedeutet in diesem Kontext, dass sie Schnittstellen zur Eingabe der Suchmuster bereitstellen, die es erlauben, zur Laufzeit die Suchmuster anzupassen und zu verfeinern.

Kleiner Bruder

Fzf ist heute bereits auf vielen Systemen als Standard-Tool im Einsatz. Seine Weiterentwicklung Fzy bietet laut ihrem Entwickler einen verbesserten Algorithmus und eine höhere Suchgeschwindigkeit. Zudem beschränkt sich Fzy auf die absolut notwendigen Optionen, was die Anwendung vereinfacht. Auf den ersten Blick wirkt Fzy tatsächlich nur wie eine Variante von Fzf, doch das täuscht. Obwohl sich die Ausgaben ähneln, kann Fzy höchstens als kleiner Bruder von Fzf gelten. Sein Einsatz erfolgt ebenfalls in einer Pipe, es gibt aber auch einen – sehr vereinfachten – Finder, der eine Art von Menü mit einem einstellbaren Prompt bietet. Damit erschöpfen sich die Ähnlichkeiten allerdings schon. Das wird insbesondere deutlich, wenn man sich die Optionen von Fzy ansieht. Voreingestellt nutzt dessen Finder nur zehn Zeilen des Terminals, um die Liste mit den Ergebnissen anzuzeigen. Das lässt sich über die Option -l ändern. Fzy kann nur mit positiven Mustern arbeiten, einen Ausschluss erlaubt es nicht. Im interaktiven Modus steht nur eine Handvoll von Tastenkürzel bereit, die die recht knappe Manpage des Tools aufführt.

Fzf

Fzf steht für Fuzzy Finder. Das Werkzeug agiert als allgemein gehaltener Filter, der im interaktiven Modus auch als Menü-Generator fungiert. Mit dem Aufruf fzf starten Sie das Tool in der Shell, was normalerweise die Anzeige aller Dateien im aktuellen Verzeichnis bewirkt. Dabei nutzt Fzf einen eingebauten Find-Befehl, der dann zum Einsatz kommt, wenn das Programm keine Daten über die Standardeingabe erhält. Das Feature hilft dabei, Befehlszeilen kurz zu halten. Sie steuern es über die Umgebungsvariable FZF_DEFAULT_COMMAND, in der Sie bei Bedarf einen anderen Befehl vorgeben. Optionen, die Sie Fzf voreingestellt mitgeben wollen, hinterlegen Sie in der Umgebungsvariablen FZF_DEFAULT_OPTS.

Meist kommt das Programm in Verbindung mit der Pipe zum Einsatz, erhält die Eingabedaten also via Standardeingabe (Listing 1). Damit landen Sie im interaktiven Modus, der aus zwei Teilen besteht. Das sichtbare Interface, der Finder, erlaubt interaktive Aktionen. In ihm manövrieren Sie mit den Pfeiltasten oder über [Strg]+[K] und [Strg]+[J]. Die aktuelle Zeile zeigt das Terminal entsprechend der Einstellungen fett oder invers an. Durch einen Druck auf die Eingabetaste übernehmen Sie die markierte Zeile und schreiben sie in die Standardausgabe beziehungsweise ins Terminal.

Listing 1

Locate und Fzf via Pipe

$ locate / | fzf
[...]
.../Bilder-sda5/_1130192.png.out.pp3
.../Bilder-sda5/_1130192-1.png.out.pp3
.../Bilder-sda5/_1110520.jpg.out.pp3
.../Bilder-sda5/_1090399.dng.xmp
.../Bilder-sda5/_1090399.dng.pp3
.../Bilder-sda5/_1040511a.pts
.../Bilder-sda5/_1040511.pts
.../Bilder-sda5/_1040511-6.pts
.../Bilder-sda5/TANZ!-2020-2021
[...]

Am unteren Rand blinkt im Finder zusätzlich ein Prompt (>) und fordert zur Eingabe auf. Haben Sie Fzf bereits beim Aufruf ein Suchmuster mitgegeben (als Argument der Option -q), steht es in dieser Zeile zum Bearbeiten bereit. Im Hintergrund arbeitet der zweite Teil, der den Index und die unscharfe Suche steuert. In der vorletzten Zeile zeigt das Tool an, was diesbezüglich gerade geschieht: Ein sich stetig änderndes Zeichen symbolisiert, dass es aus den Eingaben einen Index erzeugt, in dem es dann das Muster sucht. Die aktuelle Größe dieses Index sehen Sie ebenfalls am unteren Ende.

Suchmuster

Der Finder stellt ein wesentliches Feature von Fzf dar. Die Möglichkeiten des Tools beschränken sich jedoch nicht darauf, vorhandene Suchmuster zu bearbeiten. Es wertet die Muster außerdem inkrementell aus. Jedes zusätzlich eingegebene Zeichen verfeinert also die Suche. Im voreingestellt aktivierten Extended-Search-Modus dürfen Sie zudem weitere Muster durch Leerzeichen getrennt angeben. Einigen darin verwendeten Sonderzeichen misst das Programm spezielle Bedeutungen zu (siehe Tabelle “Suche für Profis”). Mehrere Suchmuster kombinieren Sie wie in Listing 2.

Zeichen

Beispiel

Ergebnis

^

^linux

Zeilen, die mit linux beginnen

$

linux$

Zeilen, die auf linux enden

!

!linux

Zeilen, die linux nicht enthalten

'

'linux

Zeilen, die exakt linux enthalten (keine unscharfe Suche)

sbtrkt

Token für die unscharfe Suche (Voreinstellung)

Listing 2

Suchmuster kombinieren

Muster1$ Muster2 ^Muster3 !Muster4

Innerhalb des Suchmusters im Finder navigieren Sie mit den Pfeiltasten. Die markierte Zeile signalisiert die Auswahl. Alternativ stehen einige vorab eingestellte Tastenbindungen bereit (siehe Tabelle “Steuerung”). Alle Aktionen, die die Aus- oder Abwahl mehrerer Zeilen umfassen, setzen voraus, dass Sie die Software über -m im Multiauswahlmodus starten. Daneben unterstützt der Finder auch das Steuern per Maus. Das Mausrad scrollt, Klick und Doppelklick aktivieren beziehungsweise wählen. Bei gedrückter Umschalttaste wählt ein Mausklick mehrere Elemente aus. Der Doppelklick beendet die Eingabe.

Tasten

Erläuterung

[Strg]+[K]

Nach oben.

[Strg]+[J]

Nach unten.

[Strg]+[C]

Abbrechen.

[Alt]+[F]

Ein Wort im Suchmuster nach rechts springen.

[Alt]+[B]

Ein Wort im Suchmuster nach links springen.

[Strg]+[A]

An den Anfang des Suchmusters springen.

[Strg]+[E]

Ans Ende des Suchmusters springen.

[Tab]

Mehrere aufeinander folgende Zeilen auswählen.

[Umschalt]+[Tab]

Aufeinander folgende ausgewählte Zeilen schrittweise abwählen.

[Strg]+[I]

Zeilen wahlfrei aus- oder abwählen.

Ansonsten arbeitet das Programm voreingestellt mit einer an den Emacs angepassten Tastenbindung. Mittels --bind lassen sich weitere oder abweichende Tastenbindungen einstellen. Die Befehlszeilenoption -e deaktiviert die unscharfe Suche und bewirkt, dass nur noch exakte Treffer erscheinen. Weitere wichtige Optionen von Fzf fasst die Tabelle “Wichtige Optionen” zusammen.

Option

Erläuterungen

-e/+x

Nur exakte Treffer anzeigen, unscharfe Suche deaktivieren.

+i/-i

Groß- und Kleinschreibung (nicht) unterscheiden.

--algo=v1/v2

Algorithmus auswählen: v1: schneller, v2: bessere Treffer (voreingestellt).

--disabled

Suche deaktivieren, nur Interface bereitstellen.

+s/--no-sort

Ausgabe nicht sortieren.

--tac

Reihenfolge der Eingabe umkehren.

Optionen für die Benutzerschnittstelle

+m/-m

Mehrfachauswahl (de-)aktivieren, voreingestellt: nur einen Treffer zurückgeben.

--cycle

Vor dem ersten / nach dem letzten Eintrag weitersuchen.

--height=Höhe

Höhe der Fzf-Benutzerschnittstelle.

--height Prozent

Höhe des Finders in Prozent der Terminalgröße.

-q Abfrage

Software mit Abfrage starten.

-1

Bei einzelnem Treffer den Finder nicht starten.

-0

Bei Ausbleiben eines Treffers den Finder nicht starten.

--preview Kommando

Kommando für die Ausgabe verwenden,

--preview-window

Form, Größe und Art der Vorschau festlegen.

Wie das Programm Treffer ermittelt und bewertet, steuern Sie mit einer Reihe von Parametern. Die Bewertung der Eingabezeilen erfolgt dabei anhand der Kriterien aus der Tabelle “Modifikationen”. Dabei darf index nur am Ende stehen. Diese Option verwendet Fzf als Standard, wenn Sie nichts angeben. Mit diesen Kriterien, die Sie als Argument der Option --tiebreak=Kriterium explizit auswählen, bewertet Fzf die Eingaben. Voreingestellt verwendet es length beziehungsweise length,index. Falls Sie end verwenden, wertet die Software die Zeilen rückwärts aus.

Option

Erläuterung

length

Kürzere Zeilen mit Treffern bevorzugen.

begin

Übereinstimmungen am Zeilenanfang bevorzugen.

end

Übereinstimmungen am Zeilenende bevorzugen.

index

Im Eingabestrom weiter vorn stehende Zeilen bevorzugen.

Eine typische Fzf-Anwendung besteht in der fehlertoleranten Variante des Locate-Befehls. Letzterer sucht in einer zuvor erstellten Datenbank anhand von Namen nach Dateien im lokalen System. Diese Suche erfolgt strikt, liefert also bei Schreibfehlern oder Abkürzungen keine Ergebnisse. Im Beispiel aus Listing 3 erzeugt locate / eine Liste aller Einträge und liefert diese via Pipe an Fzf. Das setzt alle übergebenen Argumente als Muster für den Befehl ein. Übergeben Sie L keine Argumente, erscheint die gesamte Liste, und Sie geben Muster im interaktiven Modus von Fzf direkt ein.

Listing 3

Unscharfe Suche mit Locate

L () { locate -i / | fzf -q "${*:-/}" ; }

Bei einer sehr großen Datenbank möchten Sie vermutlich viele Treffer ausschließen, um die Übersicht in den Ergebnissen zu erhöhen. Das erledigen Sie, indem Sie der Funktion Argumente übergeben. In Listing 4 sucht das Muster nach “etwas”, schließt dabei aber “anderes” aus. Wenn das immer noch zu viele Treffer liefert, etwa in den zufällig benannten Browser-Caches, führen weitere zusätzliche Muster im interaktiven Modus zu besseren Ergebnissen. Das Ausrufezeichen vor dem ausschließenden Muster maskieren Sie beim Aufruf in der Bash mit einem Backslash, anderenfalls interpretiert die Shell das Zeichen als History-Befehl und entfernt es aus der Befehlszeile.

Listing 4

Ausschluss von Treffern

> L etwas \!anderes
[...]
.../Musik/The Temptations -  Papa was a rolling stone.mp3.mp3
.../Bilder/png/2-wasserzeichen.png
.../Musik/Frumpy - How the Gypsy was Born.mp3
.../Musik/2/Bots - Was wollen wir trinken.mp3
.../Musik/Byron Metcalf - Heart Warriors+.mp3
.../Bilder/luftbild nokanal wassergrenze.png
[...]

Fzf unterstützt bei den Treffern einen ausgefeilten Vorschaumodus. Als Argument der Option --preview dient dabei eine Befehlszeile zum Erzeugen der Vorschau. Diese erscheint für die aktuelle, mit dem Cursor ausgewählte Datei in einem eigenen Fenster, das Fzf auf der rechten Seite erzeugt (Abbildung 1). Für die Ausgabe in Terminals eignen sich nur Textausgaben, sodass bei vielen Dateien die Metadaten oder die zuvor umgewandelten oder extrahierten Textinhalte anstatt der binären Daten in der Vorschau erscheinen.

Abbildung 1: Mit <code>fzf --preview 'less {}'</code> bietet das Programm eine Vorschau &uuml;ber den Pager Less an, die sich aber in erster Linie f&uuml;r Textdateien eignet.

Abbildung 1: Mit fzf --preview 'less {}' bietet das Programm eine Vorschau über den Pager Less an, die sich aber in erster Linie für Textdateien eignet.

Eine große Hilfe leistet Less als universelle Vorschau (Listing 5), da sich der Pager mittels Lesspipe [6] besonders gut zur Anzeige unterschiedlicher Dateitypen eignet. Es genügt daher, als Befehl --preview 'less {}' anzugeben, weil dieser Befehl schon bei korrekt installierter Lesspipe direkt in der Lage ist, etwa den Inhalt von Textdateien anzuzeigen, aber auch den von Archiven oder die Metadaten von Multimedia-Dateien.

Listing 5

Treffervorschau

$ fzf --preview 'Vorschaubefehl'

Sowohl die Position als auch die Größe des Vorschaufensters stellen Sie über die Option --preview-window Position ein. Die wesentlichen Argumente dieser Option sind die Position (top, bottom, left, right), die Größe (in Prozent der Terminalbreite) und der Modus (wrap, cycle und hidden). Diese Angaben geben Sie ohne Leerzeichen und nur durch Doppelpunkte getrennt am Stück ein (Listing 6).

Listing 6

Position der Vorschau

$ fzf --preview-window=top:55%:wrap:cycle

Neben der Vorschau gibt es mit den Aktionen eine weitere Möglichkeit, eine Ansicht der Inhalte zu generieren. Im Programm umfassen die Actions eine ganze Gruppe von Funktionen, die Sie im interaktiven Finder aktivieren. Sie triggern die Actions außerdem durch sogenannte Events. Als solche erkennt Fzf derzeit nur change, wenn sich die Suchanfrage ändert, sowie backward-eof, falls die Suchanfrage leer ist und Sie dennoch mittels [Rückschritt] versuchen, sie zu löschen. Das Change-Event kommt oft zusammen mit first (zum ersten Treffer springen) zum Einsatz, für backward-eof ist abort (Aktion abbrechen) voreingestellt.

Tastenbindungen

Als Besonderheit erlaubt es Fzf, aus dem laufenden Programm heraus weitere Programme aufzurufen. Dieses über die Aktion execute gesteuerte Verfahren bietet vielfältige Möglichkeiten. So öffnen Sie etwa ausgewählte Dateien, um sie dann anzusehen oder zu bearbeiten. Als Argument der Aktion execute erwartet Fzf eine Befehlszeile, die es dann in einer Subshell ausführt. Die Zeichenkette {} steht dabei für die ausgewählten Dateien.

Die Option --bind dient dazu, um Aktionen auf eine Taste oder eine Tastenkombination zu legen. Dabei dürfen Sie mehr als eine Aktion bei einer Tastenbindung verwenden, was ein Beispiel aus der Manpage (Listing 7) praxisnah demonstriert. Beide Formen sind gleichwertig.

Listing 7

Tastaturbindungen definieren

fzf --multi --bind 'ctrl-a:select-all+accept'
fzf --multi --bind 'ctrl-a:select-all' --bind 'ctrl-a:+accept'

Das Erstellen eigener Definitionen ermöglicht es, die Bedienung von Fzf an die anderer Programme anzupassen oder neue Funktionen bereitzustellen. Um das Argument von --bind zusammenzufassen, schließen Sie es in einfache oder doppelte Hochkommas ein, falls es Leerzeichen enthält.

Fzf stellt in der aktuellen Version nur eine Teilmenge der Tasten für Bindungen bereit (Tabelle “Unterstützte Tasten”). Andere Kombinationen, wie [Umschalt]+[Eingabe], ignoriert das Programm mit einer Warnung wie un-Supported key: shift-enter. Dafür akzeptiert die Software Mausklicks zusammen mit [Pfeil-oben]+[Pfeil-unten] sowie Doppelklicks. Viele Aktionen löschen schlicht Zeichen oder springen zu bestimmten Positionen in der Zeile. Die Tabelle “Aktionen” fasst einige andere, speziellere Funktionen zusammen. Die meisten davon sind normalerweise nicht an Tasten gebunden, stehen also voreingestellt nicht bereit.

Gruppe

Tasten

Einfache Tasten

[Eingabe]+[Leer]+[Umschalt]+[Leer][Tab]+[Umschalt]+[Tab][Esc]+[Entf]+[Pfeil-oben]+[Pfeil-unten]+[Pfeil-rechts]+[Pfeil_links]+[Pos1]+[Ende]+[Einf]+[F1] bis [F12]+[A] bis [Z]

Kombinationen mit [Strg]

[Leer]+[AltGr]+[ß][AltGr]+[ 9][^]+[Umschalt]+[ 7][A] bis [Z]

Kombinationen mit [Alt]

[Leer]+[Pfeil-oben]+[Pfeil-unten]+[Pfeil-rechts]+[Pfeil-links]+[Rückschritt]+[A] bis [Z]

Kombinationen mit [Umschalt]

[Pfeil-oben]+[Pfeil-unten]+[Pfeil-rechts]+[Pfeil-links]

Dreierkombinationen

[Strg]+[Alt]+[A] bis [Strg]+[Alt]+[Z][Alt]+[Umschalt]+[Pfeil-oben][Alt]+[Umschalt]+[Pfeil-unten][Alt]+[Umschalt]+[Pfeil-rechts][Alt]+[Umschalt]+[Pfeil-links]

Aktion

Erläuterung

accept

Aktuellen Eintrag übernehmen

accept-non-empty

Ist ein Eintrag ausgewählt, diesen übernehmen

change-prompt

Finder-Prompt ändern

clear-selection

Zuvor markierter Einträge abwählen

preview

Vorschau zeigen

refresh-preview

Vorschau erneuern

select-all

Alles auswählen

deselect-all

Alles abwählen

toggle-all

Alle Treffer umschalten

toggle-search

Suche umschalten

toggle-preview

Vorschaufenster (nicht) zeigen

toggle-sort

Sortieren umschalten

disable-search

Deaktiviert die Suche

reload

Index erneut einlesen und aufbauen

replace-query

Ersetzt die Suche durch die aktuelle Auswahl

unbind

Mittels --bind erzeugte Tastenbindung löschen

Das Ausführen externer Befehle lässt sich auf zwei Arten erledigen. Mittels der Aktion execute führt Fzf die Befehlszeile aus, wartet bis zum Ende des Befehls und zeigt dann dessen Ausgabe. In vielen Fällen ist das genau das gewünschte Verhalten. Um zu verhindern, dass Fzf wartet – und damit keine Eingaben mehr akzeptiert – schicken Sie die ausgeführten Befehle durch ein angehängtes Ampersand in den Hintergrund. Benötigen Sie die Ausgabe der ausgeführten Befehle nicht, nutzen Sie die Aktion execute-silent. Das Programm startet dann die Befehle, verwirft aber die Ausgabe.

Fazit

Sowohl Fzf als auch Fzy sind nützliche, gut anwendbare Tools, die die Arbeit in vielen Bereichen erleichtern und beschleunigen. An Fzf gefallen die Vielfalt der Funktionen, die flexiblen Möglichkeiten, das Terminal aufzuteilen, sowie insbesondere die Aktionen. Bei Fzy stechen hingegen dessen Schlichtheit und das optionale Einblenden des Scorings ins Auge. Beiden Werkzeugen fehlt allerdings die Möglichkeit, gezielt Einfluss auf die Algorithmen zu nehmen, wie das etwa Agrep erlaubt. (tle/agr)

Infos

  1. Levenshtein-Distanz: https://de.wikipedia.org/wiki/Levenshtein-Distanz

  2. Agrep: Karsten Günther, “Besser finden”, LU 01/2016, S. 70, https://www.linux-community.de/35929

  3. Ugrep: Karsten Günther, “Aufgespürt”, LU 01/2021, S. 14, https://www.linux-community.de/45289

  4. Fzf: https://github.com/junegunn/fzf

  5. Fzy: https://github.com/jhawthorn/fzy

  6. Lesspipe: Christian Perle, “Mehrfunktionen eingespeist”, LU 04/2002, S. 60, https://www.linux-community.de/2081

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDF
LinuxUser 03/2022 KAUFEN
EINZELNE AUSGABE
ABONNEMENTS
TABLET & SMARTPHONE APPS
E-Mail Benachrichtigung
Benachrichtige mich zu:

Hinweis: Dieser Artikel ist älter als ein Jahr, enthaltene Informationen sind möglicherweise veraltet.

0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben