blog · git · desktop · images · contact & privacy · gopher


explain: Befehle mit ASCII-Art erklären

Im Posting zu "sed" und den INI-Dateien kam in den Kommentaren die Frage von posativ auf, ob ich die erklärenden "Bildchen" für die Befehle selbst geschrieben hätte oder ob es dafür ein Tool gäbe. Gemeint war soetwas hier:

sed 's/hurz/herz/' < eingabe > ausgabe
    \------+-----/ \--------+--------/
           |                |
           |                \- Lies dabei aus "eingabe" und schreibe
           |                   nach "ausgabe".
           |
           \- Ersetze "hurz" mit "herz".

Sie waren von Hand geschrieben. Die Idee ist aber cool gewesen und zumindest ich kenne so ein Tool auch nicht, was das erstellen könnte. Eigentlich braucht man das aber ziemlich oft und es wäre äußerst praktisch. Unglaublich viel Prosa und einige Missverständnisse könnte man vermeiden. Und was macht man in solch einer Situation? Man behebt den Mangel. ;)

Den Abend habe ich also nun damit verbracht, da mal etwas Schönes zu basteln. Herausgekommen ist "explain" und das findet man dort: explain.py.

Aufgerufen wird das Skript mit "./explain.py dateiname", wobei der Parameter "--help" alle verfügbaren Optionen auflistet, insbesondere sei da die gewünschte Zeilenlänge zu nennen (die jedoch automatisch nach oben korrigiert wird, falls der Befehl länger ist). In "dateiname" steht nun der zu erklärende Befehl mitsamt den Erklärungen -- hier der "Quellcode" für obiges Beispiel:

sed 's/hurz/herz/' < eingabe > ausgabe
    -------------- -------------------

Ersetze "hurz" mit "herz".

Lies dabei aus "eingabe" und schreibe nach "ausgabe".

Das ist die einfachste Form. Man markiert mit Minuszeichen die verschiedenen Bereiche, dann eine Leerzeile (optional, aber schöner für's Auge), dann die einzelnen Kommentare wieder getrennt durch eine Leerzeile. Die Kommentare werden dabei von links nach rechts zugeordnet -- so, wie man oben auch die Bereiche markiert. Sie können umgebrochen und auf mehrere Zeilen verteilt sein, das spielt keine Rolle.

Wie man sieht, erkennt das Skript Bereiche anhand von Leerzeichen: Eine Reihe von Minuszeichen und dann mindestens ein Leerzeichen, das markiert einen Bereich. Was aber, wenn zwei Bereiche direkt aneinander grenzen? Dann kann der letzte Teil eines Bereiches alternativ mit einem Pluszeichen markiert werden:

sed 's/hurz/herz/i' < eingabe > ausgabe
    ------------+-  -------------------

Ersetze "hurz" mit "herz".

Nicht case-sensitive.

Lies dabei aus "eingabe" und schreibe nach "ausgabe".

Das Ergebnis dessen ist:

sed 's/hurz/herz/i' < eingabe > ausgabe
    \-----+-----/|  \--------+--------/
          |      |           |
          |      |           \- Lies dabei aus "eingabe" und schreibe
          |      |              nach "ausgabe".
          |      |
          |      \- Nicht case-sensitive.
          |
          \- Ersetze "hurz" mit "herz".

Weiterhin kann es auch vorkommen, dass man mehrere einzelne Zeichen direkt nacheinander mit Kommentaren versehen will. Dann funktioniert die Schreibweise mit dem Pluszeichen nicht mehr. Dafür habe ich ein Ausrufezeichen eingebaut, was ein einzelnes Zeichen markiert:

sed 's/[a-z,]/haha/' <<<'Hallo, Welt!'
       !---!! ----   -----------------

Hier fängt eine character class an.

Zeichen von "a" bis "z".

Zusätzlich auch das Komma.

Hier hört die Klasse auf.

Womit soll es ersetzt werden?

Übergib einen "Here-String" (Bash).

Dabei sei noch angemerkt, dass ein Ausrufezeichen auch gleichzeitig als Pluszeichen agiert, wenn vorher ein normaler Bereich kam. Resultat:

sed 's/[a-z,]/haha/' <<<'Hallo, Welt!'
       |\+/|| \-+/   \-------+-------/
       | | ||   |            |
       | | ||   |            \- Übergib einen "Here-String" (Bash).
       | | ||   |
       | | ||   \- Womit soll es ersetzt werden?
       | | ||
       | | |\- Hier hört die Klasse auf.
       | | |
       | | \- Zusätzlich auch das Komma.
       | |
       | \- Zeichen von "a" bis "z".
       |
       \- Hier fängt eine character class an.

Als kleines Schmankerl kann man mit den Parametern "-c", "-s", "-r" und "-j" das Aussehen des Graphen verändern. Ein Unicode-Preset gibt es auch, das mit "-u" aktiviert wird -- das ist dann zwar nicht mehr "ASCII-Art", aber was soll's. ;) Apropos Unicode: Die Dateien mit Befehl und Kommentaren werden UTF-8-kodiert erwartet. Standardmäßig ist die Ausgabe auch immer UTF-8, was man aber mit "-8" abschalten kann -- dann entscheidet Python selbst, was passieren soll. Was auch immer das sein möge.

– Nachtrag: Achwas. Das Skript ist in den News des Linux-Magazins gelandet. :)

Im letzten Satz wird erwähnt, dass eine Lizenz fehlt. Stimmt, hab' ich nicht dran gedacht, weil das Skript so kurz ist. Betrachtet es hiermit als Pizzaware, eine Spielart der Beerware.