Erweiterte Dateiattribute mit Zenity in Thunar einbinden

Do, 2. Februar 2023, Ralf Hersel

Ich bin sehr enttäuscht. Jetzt wollte ich einen schönen Artikel darüber schreiben, wie man die erweiterten Dateiattribute mit den einfachen Zenity-Dialogen im Dateimanager Thunar einbindet, da schreibt ein Leser, dass die Attribute bei einer Änderung der Datei überschreiben werden. Um zu verstehen, worum es geht, solltet ihr den oben erwähnten Artikel lesen.

Damit ich nicht vergebens daran gearbeitet habe, schreibe ich diesen Artikel trotzdem, um meinen Misserfolg für die Nachwelt zu erhalten. Die Idee war es, die erweiterten Dateiattribute direkt aus einem Dateimanager (Thunar oder andere) bearbeiten zu können. Dazu habe ich zwei Skripte geschrieben und diese in Thunar eingebunden. Das erste Skript erlaubt es, einer Datei beliebige Tags und Werte zuzuordnen; mit dem zweiten Skript kann man diese Attribute anschauen. Ein drittes Skript hätte das Löschen der Attribute erlaubt. Aufgrund der oben genannten Gründe habe ich das nicht gemacht.

Fast alle Dateimanager erlauben Erweiterungen durch den Aufruf von Skripten. Das können Shell-Skripte oder Python-Programme oder sonst etwas sein. Die Dateimanager übergeben dabei diverse Parameter, wie den Pfad der ausgewählten Datei, oder eine Liste von Dateien und noch mehr. Die Dokumentation für Thunar findet ihr hier und für Nautilus dort. Warum ich als GNOME-Anwender Thunar statt Nautilus verwende, könnt ihr in diesem Beitrag lesen.

Genug der Vorworte. Hier sind die zwei Skripte:

Beim Ersten handelt es sich um ein Shell-Skript, welches setfattr aufruft, um im Namespace user ein neues Attribut zu erzeugen und mit einem Wert zu belegen. So sieht es aus:

#!/bin/bash
# Thunar extension
# add attribute/value to file

result=$(zenity --title "Attribute" --forms --text "Set Attribute" --add-entry "Attribute" --add-entry "Value")
attribute=$(echo $result | cut -d "|" -f 1)
value=$(echo $result | cut -d "|" -f 2)
setfattr -n user.$attribute -v $value $1

Darin wird ein Zenity-Formular mit zwei Feldern aufgerufen: Name des Attributs und Wert des Attributs. Das Skript heisst setattr.sh und kann in die Benutzerdefinierten Aktionen aufgenommen werden. Dem Skript übergibt Thunar mit dem Parameter %f die ausgewählte Datei. Mit %F können auch mehrere ausgewählte Dateien übergeben werden.

Dann findet man in Thunar nach einem Rechtsklick auf eine Datei den Menüpunkt Set Attribute vor, mit dem sich ein Dialog öffnet, in dem Attributname und Wert eingetragen werden können (siehe Titelbild). Die Vergabe von Attributen kann man weiterführen; im Beispiel habe ich Farbe, Grösse und Verwendung eingetragen.

Das zweite Skript kümmert sich um die Anzeige der Attribute für eine Datei. Dieses heisst Show Attributes und erscheint ebenfalls im Kontextmenü einer Datei in Thunar. Man könnte es erweitern, sodass Attribute für mehrere ausgewählte Dateien gesetzt werden können. Im ersten Ansatz wollte ich dieses Skript auch als Shell-Skript implementieren. Beim Parsen von komplizierten Strings ist ein Shell-Skript keine gute Empfehlung; da ist man mit Python besser beraten. Daher habe ich das zweite Skript in Python geschrieben. An dieser Stelle geht ein herzlicher Dank an die GNU/Linux.ch-Community für ihre Unterstützung.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Thunar extension
# show attributes/values of a file

import subprocess

def shell(command):                                                             # run shell command and return the output
    p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
    stdout = p.stdout
    return stdout    

def main(args):
    lines = shell(f'getfattr -d {args[1]}')                                     # get file attributes and values
    next(lines)                                                                 # skip first line (contains file name)
    content = []
    for line in lines:
        line = line.decode()                                                    # convert to something readable
        if not line.strip(): continue                                           # skip the empty last line
        entry = line.strip().split('=')                                         # kick out white chars and convert to list
        attribute = entry[0].replace('user.', '')                               # remove leading namespace
        value = entry[1].replace('"', '')                                       # remove surrounding "
        content.append([attribute, value])
    all = ''
    for i in content:                                                           # flatten the list to one space separated string
        all += ' '.join(i)
        all += ' '
    shell(f'zenity --title "Attribute" --list --column "Attribute" --column "Value" {all}')
    return 0

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Die genaue Erklärung aller Schritte im Skript führt wohl etwas zu weit. Daher nur ganz kurz. Die Funktion shell führt ein Shell-Kommando aus und liefert dessen Ausgabe zurück. Getfattr holt die Attribute der Datei. Im Original sieht das so aus:

getfattr -d test_1.txt

# file: test_1.txt
user.Farbe="rot"
user.Grösse="37"
user.Verwendung="Artikel"

Bei der Ausgabe sieht man gut, dass einiges an Parsing nötig ist, um zu den Strings: Farbe und rot zu gelangen. Im Gegensatz zum Shell-Skript ist das in Python kein Problem. Der Zenity Listendialog erwartet eine Leerzeichen-separierte Liste aller Werte in einem String. Das ist die Variable all im Skript. Wie das Ergebnis aussieht, seht ihr im Titelbild. Das Skript nimmt die Shell-Ausgabe entgegen, iteriert über die Zeilen der Ausgabe, schält die Attribute und Werte aus den Zeilen heraus und schreibt diese in die Liste content. Die Liste wird in der zweiten For-Schleife flach geklopft, damit ein kompletter Attribute-Werte-String entsteht, den Zenity gerne haben möchte.

Ich denke, ihr geht mit mir einig, dass diese Übung in Shell-Skript viel schwieriger gewesen wäre.

Man könnte noch ein drittes Skript erstellen, mit dem sich Attribute löschen lassen. Der Befehl dafür lautet:

setfattr -x user.$1 $2

Für die Umsetzung könnte man das zweite Skript wiederverwenden und den Löschbefehl für eine ausgewählte Zeile erweitern. Doch dazu wird es nicht kommen, weil die ganze Geschichte aus zweierlei Hinsicht hoffnungslos ist:

  1. Damit das Taggen von Dateien im Dateimanager zu einer hilfreichen Funktion wird, müssten die Attribute und Werte als Spalte integriert werden, sodass man sie sofort sehen und damit arbeiten kann. Zum Beispiel Sortieren und Suchen.

  2. Die Tatsache, dass die erweiterten Dateiattribute beim Ändern einer Datei verloren gehen, macht die Sache überflüssig. Da frage ich mich, warum es sie überhaupt gibt.

Trotz der Sinnlosigkeit hoffe ich, dass euch der Artikel ein wenig Wissen und Praxis vermittelt hat. Es gibt viele Möglichkeiten, den eigenen Dateimanager mit Skripten zu erweitern. Und vielleicht werden wir eines Tages ein Dateisystem erblicken, das Tagging nativ unterstützt.

Update

Beachtet bitte die Kommentare, in denen erklärt wird, dass es an den Anwendungen liegt, ob Dateiattribute behalten oder überschrieben werden. Somit handelt es sich nicht um ein Problem des Dateisystems, sondern wie die Anwendungen mit Dateien umgehen.

Tags

Thunar, Zenity, Dateiattribute, Tags, Shell-Skript, Python