1 Punkte von GN⁺ 2024-05-02 | 1 Kommentare | Auf WhatsApp teilen
  • ffs (file filesystem) ist ein Tool, das halbstrukturierte Daten wie JSON, YAML und TOML als Dateisystem mountet, damit sie mit Unix-Shell-Tools durchsucht und bearbeitet werden können
  • Die Unix-Shell bietet viele Werkzeuge zur Zeichenkettenverarbeitung, ihre grundlegende Datenstruktur ist jedoch das Dateisystem; für das Bearbeiten baumförmiger Daten ist sie daher nicht gut geeignet
  • ffs [file] verbindet eine Datei mit einem Mountpoint und gibt beim Unmounten das aktualisierte Ergebnis auf stdout oder in eine angegebene Ausgabedatei aus
  • Das Schreiben von Dateien und Anlegen von Verzeichnissen wird in JSON-Schlüssel und -Objekte umgewandelt; 1, true, false sowie leere Dateien werden jeweils als Zahl, boolescher Wert bzw. null übernommen
  • Unter Linux wird FUSE benötigt, unter macOS macFUSE; für Windows, Umgebungen ohne FUSE, reine Suchaufgaben oder sehr große Dateien kann es ungeeignet sein

Halbstrukturierte Daten wie Verzeichnisse behandeln

  • ffs steht für file filesystem und mountet halbstrukturierte Daten wie ein Dateisystem, damit man mit vertrauten Shell-Tools damit arbeiten kann
  • Derzeit unterstützte Formate sind JSON, YAML und TOML; Unterstützung für weitere Formate ist geplant
  • Eine ausführliche Anleitung findet sich in der ffs-Manpage

Mount- und Bearbeitungsablauf

  • Der grundlegende Aufruf lautet ffs [file]; dabei wird file.blah am Mountpoint file gemountet und die endgültig aktualisierte Version auf stdout ausgegeben
  • Mit ffs -m MOUNT file kann ein expliziter Mountpoint angegeben werden, mit -o OUTPUT eine Ausgabedatei
  • ffs -i file bearbeitet die Datei direkt; beim Unmounten des Volumes wird das Ergebnis wieder in file geschrieben
  • In den Beispielen sichtbare Umwandlungsregeln

    • echo Mikey Indiana >object/name ändert den JSON-Wert name
    • echo 1 >object/nose wird nicht als Zeichenkette, sondern als Zahl 1 übernommen
    • mkdir object/pockets und die Dateien darin werden in ein JSON-Objekt umgewandelt
    • Die leere Datei mistakes wird in JSON als null gespeichert

Installationsvoraussetzungen und Distribution

  • Unter Linux wird FUSE benötigt
  • Unter macOS wird macFUSE benötigt
  • Aktuelle Entwicklungs-Builds werden als einzelne ausführbare Dateien für Linux und macOS bereitgestellt
  • Bestimmte Releases sind auf der Release-Seite zu finden; die aktuelle Version ist 0.1.2
  • Es kann auch aus dem Quellcode gebaut werden

Zugehörige Materialien und Vergleichspunkte

  • Es gibt den PLOS-2021-Artikel „Files-as-Filesystems for POSIX Shell Data Processing“
  • jq und gron sind Tools für den Umgang mit JSON auf der Kommandozeile
  • ffs unterscheidet sich dadurch, dass es mehrere Formate unterstützt, die Bearbeitung mit vertrauten Shell-Tools ermöglicht und keine neue Sprache erfordert
  • Windows-Nutzung, fehlende FUSE-Unterstützung, Aufgaben, bei denen nur gesucht werden muss, sowie sehr große Dateien können für ffs ungeeignet sein
  • Die Lizenz ist GPLv3

1 Kommentare

 
GN⁺ 2024-05-02
Meinungen auf Hacker News
  • Das ist cool. Ich habe kürzlich libfuse in Nim gewrappt und das hello-Dateisystem-Beispiel portiert, und dabei fast dasselbe gebaut.
    Bei meiner Version muss man Daten per Pipe einspeisen und einen Mount-Punkt angeben; am Ende schreibt sie das Ergebnis auf die Standardausgabe. Dadurch lässt sie sich in eine Pipe-Kette einfügen, aber man muss sich auch selbst um die Ausgabe kümmern.
    Im Moment erkunde ich, ob sich auch andere Dinge als Dateisysteme umsetzen lassen. Ich habe auch eine Statusleiste für den Nimdow-Fenstermanager gebaut: Schreibt man Inhalte in einzelne Dateien, entsteht als Ausgabe eine Leiste mit Blöcken, sodass sich der Inhalt der Leiste leicht austauschen lässt.
    Ein weiteres Tool, das ich gebaut habe, ist ein Musikplayer auf Basis von libvlc. Man gibt ihm einen Ordner, er liest Medien mit ID3-Tags ein und baut Ordner wie by-artist und by-album auf. Jede Datei heißt - und enthält den vollständigen Pfad zur tatsächlichen Datei. Um einen Song abzuspielen, macht man zum Beispiel ein cat einer Datei nach control/current und schreibt play nach control/command. Es gibt noch Playlist-Funktionen und weitere Befehle, aber das Ziel ist ein sehr gut skriptbarer Musikplayer.

    • Eine Idee: Code-Dateien oder Projekte rekursiv mounten. Mit etwas wie tree-sitter könnte man Klassen- und Funktionsdefinitionen extrahieren und jede davon als „Datei“ in einem Verzeichnis anlegen, das die echte Datei repräsentiert.
      Wenn man die Struktur einer Codebasis verstehen will, führt man einfach tree aus :)
      Wenn man tiefer geht, könnte man Imports vielleicht als symbolische Links o. Ä. auflösen; da gibt es viele interessante Möglichkeiten.
    • Ich würde gern wissen, ob du den Nim-Code teilen kannst. Ich wollte schon seit einiger Zeit etwas mit FUSE ausprobieren und nutze Nim in einigen Projekten.
    • Ich fände es gut, wenn es eine eingebaute Möglichkeit gäbe, Prozessinformationen einfach als Dateisystem offenzulegen.
      Zum Beispiel cat /proc/$pid/fs/current_track, um den aktuellen Songnamen eines Musikplayers zu bekommen, oder ls /proc/$pid/fs/tabs, um die Liste offener Tabs eines Browsers zu sehen. Vielleicht könnte man sogar HTML oder eingebettete Bilder abrufen.
      Mit FUSE ist das heute zwar möglich, aber es ist umständlich, daher macht es niemand.
  • Es ist nützlich genug, dass es meiner Meinung nach eine Standardfunktion auf Betriebssystemebene sein sollte.
    Unix-artige Betriebssysteme können Disk-Images mounten und deren Inhalt durchsuchen. Aber wenn man Dateien innerhalb von Dateien durchsucht, gibt es sehr viel mehr nützliche Formate. Komprimierte Archive sind das naheliegende Beispiel.
    Einige Dateimanager unterstützen das, aber ich denke nicht, dass die Anwendungsschicht der optimale Ort dafür ist. Man könnte es wohl wie Treiber pro Dateiformat implementieren.

    • Was wirklich nötig ist: eine Möglichkeit, für jedes Dateiformat einen Mount-Befehl zu schreiben, sowie ein separater Befehl, der das Dateiformat erkennt und passend dispatcht. Vermutlich wäre das ähnlich wie der Befehl file, und all das sollte im Userspace möglich sein.
      Der einzige Faktor, der das derzeit verhindert, ist, dass MacOS keine Userspace-Dateisystem-API bereitstellt. Unter Linux, Windows und BSD ist es bereits möglich.
      Falls Apple-Entwickler mitlesen: File-Provider-Erweiterungen reichen nicht. Gebt uns ein Äquivalent zu FUSE. Ich weiß, dass es existiert.
    • Es gibt bereits avfs. Das macht genau das als FUSE-Dateisystem. Die Nutzung ist nicht gerade am intuitivsten, aber es funktioniert und ist erweiterbar.
      https://avf.sourceforge.net/
    • Das war ein zentrales Design-Feature von reiserfsv4, aber Linux hat am Ende die Aufnahme verweigert. Der Mord an seiner Frau hat vermutlich auch nicht geholfen.
    • Ganz ehrlich gefragt: Wozu ist das nützlich? Ich sehe keine Anwendungsfälle, die in der Praxis wirklich hilfreich wären.
    • Ich dachte, archivemount macht das bereits; übersehe ich etwas?
      Jedenfalls scheint FUSE, selbst wenn das nicht genau das ist, was du willst, ein allgemeinerer Mechanismus zu sein, mit dem man das Gewünschte umsetzen kann — und noch mehr.
  • Man kann auch Git-Commits als Dateisystem mounten.
    https://jvns.ca/blog/2023/12/04/mounting-git-commits-as-fold...
    Früherer Beitrag: https://news.ycombinator.com/item?id=38527866

    • Jetzt braucht man nur noch einen riesigen Haufen Regeln, der entscheidet, welche Revision gewählt wird, und schon hat man diesen unheiligen Dämon namens Rational ClearCase.
  • Beim Titel dachte ich, es sei etwas, wonach ich früher gesucht hatte oder das ich selbst bauen wollte. Vielleicht ist das hier ein guter Ort, um zu fragen.
    Gibt es ein FUSE-Dateisystem, das während des Mounts wie tmpfs im Speicher arbeitet und beim Unmounten in eine einzelne Datei auf der Festplatte serialisiert?
    Am nächsten kommen dem FUSE-Treiber, die Archivdateien mounten, aber damit bekommt man Dinge wie symbolische Links schwer hin.

    • Das Nächste, was ich gefunden habe, ist https://github.com/guardianproject/libsqlfs.
      libsqlfs implementiert ein POSIX-artiges Dateisystem auf einer SQLite-Datenbank. Es bietet ein les- und schreibbares Dateisystem mit eigener Hierarchie und eigenem Namensraum innerhalb einer einzelnen Datei und kann als Shared Library oder FUSE-Modul verwendet werden.
    • Es ist nicht rein speicherbasiert, aber etwas wie https://github.com/jrwwallis/qcow2fuse könnte vielleicht funktionieren.
      Im Vergleich zu DMG auf OSX ist es grob, aber großzügig betrachtet erfüllt es einen ähnlichen Zweck.
      Oder man könnte tmpfs wrappen und es so bauen, dass es beim Unmounten in einen Tarball serialisiert, der symbolische Links bewahrt.
    • Warum muss es unbedingt im Speicher sein?
      Wie du wahrscheinlich schon weißt, gibt es viele realistische Szenarien, in denen das Flushen von Puffern erst beim Unmounten zu Datenkorruption führen kann.
      Trotzdem sieht das Problem, das du lösen willst, interessant aus.
    • Muss es unbedingt FUSE sein? Kann man nicht ein Disk-Image per Loopback mounten?
    • Mir fällt nichts ein, das genau das tut, aber man käme dem ziemlich nahe, wenn man eine Image-Datei nach /tmp kopiert, damit arbeitet, sie unmountet und anschließend auf die Festplatte verschiebt.
  • Es gibt auch das Parts-of-file File System: https://www.usenix.org/conference/2005-usenix-annual-technic...

  • Das erinnert mich an TabFS von Omar Rizwan: <https://omar.website/tabfs/>

  • Ich habe das 2003 ausprobiert. Es war überraschend schnell und machte feingranulares Locking einfach.
    Ich habe es als Datenbank pro Nutzer in einer Web-Template-Sprache für ein riesiges Website-Erstellungstool verwendet.

  • Beim Titel dachte ich, es sei ein Meme.
    Aber es ist wirklich eine clevere Idee. Persönlich mache ich die meiste Datenverarbeitung in höherstufigen Sprachen und weiß daher nicht, ob ich es direkt nutzen würde, aber ich denke, es wird Leute geben, die Anwendungsfälle dafür finden.
    Ein guter Ansatz, der über den Tellerrand hinausdenkt.

  • Das sieht wirklich gut aus, und ich sollte es so schnell wie möglich ausprobieren.
    Es scheint sich gut dafür zu eignen, innerhalb von JSON-Dateien zu navigieren oder zu suchen.

  • Wenn dich das interessiert, könnte auch Solvent-Configr spannend sein.
    https://aws.amazon.com/marketplace/pp/prodview-i3ym46leenag4
    Es modelliert Objekte über Dateisystem-Mechanismen, sodass man objektbasierte Lösungen mit dateisystemartiger Navigation entwerfen kann.
    Demo: https://youtu.be/XgTgubZQPHw