CLI-Adventskalender, Tag 10: Tabellenkalkulation

CLI-Adventskalender: Tabellenkalkulation

Avatar von Eric

Den zweiten Advent begehen wir mit Tabellenkalkulation in der Konsole. Quasi eine kleine Gruselgeschichte …

Microsoft Excel. Die gesamte Finanzwelt und viele Unternehmen laufen darauf. Aus der Sicht altehrwürdiger Sprachen wie awk (1977) – älter als Perl (1987), die als Ersatz zu awk konzipiert wurde – und Python (1991), sieht Excel aus wie eine vorübergehende Mode-Erscheinung.

Ich gehe heute nicht darauf ein, ob man mit Konsolenbefehlen ohne sich zu verbiegen einen vollständigen Excel-Ersatz schaffen kann (ich verstehe dazu noch zu wenig von der tiefen Magie von Excel). Ich weiß aber, was ich so für meine persönlichen Probleme mit Tabellenkalkulationsprogrammen mache und das kriege ich ausgezeichnet hin!

Tabellenkalkulation und priorisierte Einkaufslisten

Wenn ich in ein Hobby einsteige, ist es meistens mit einem „Rabbit Hole“ verbunden. Ich verbringe viel Zeit damit, mich in das Thema reinzulesen, YouTube-Videos zu schauen und Equipment zu kaufen, dass ich dann ordentlich verstauen kann, wenn meine aktuelle Obsession erst einmal vorbei ist. Leider (oder glücklicherweise) ist meine aktuelle Barschaft immer etwas begrenzt, weswegen ich meine Einkäufe etwas einschränken muss.

name, anzahl, preis, prio, url
Goldpinsel, 3, 42.00, 1, https://example.com/goldpinsel
Goldfarbe, 1, 12.00, 1, https://example.com/goldfarbe
Silberfarbe, 2, 9.00, 2, https://example.com/silberfarbe
Bronzepinsel, 1, 44.00, 3, https://example.com/bronzepinsel
Goldpapier, 100, 1.21, 1, https://example.com/goldpapier

Der Schlüssel zum flüssigen Arbeiten liegt im Setup:

touch script.sh
chmod +x script.sh

inotifywait -m -r -e modify . | while read -r EVENT
do
  ./script.sh
done

Das gibt uns ein Konsolenfenster, in dem unser Skript ausgeführt wird. Und zwar jedes Mal, wenn eine Datei im Verzeichnis verändert wird.

  • -m für endloses Monitoring
  • -r für rekursiv über alle Unterverzeichnisse
  • -e um die Events zu spezifizieren, auf die wir hier achten (eine vollständige Liste aller Möglichkeiten findet ihr auf man inotifywait)

Dann schreiben wir mal ein kleines Skript (in unserer script.sh) … vorher reden wir aber über awk.

awk

awk ist der große, gemeine Bruder von cut, der ein paar Jahre im Knast gesessen und kräftig trainiert hat, aber seitdem auch mit einem komischen Akzent redet.

cut -d, -f2,3 data.csv

Schneide jede Zeile dieser Datei (oder der ankommenden Pipe) beim Komma und gib mir Feld 2 und 3. awk macht genau das.

awk -F, '{print $2, $3}' data.csv

Es ist eine vollwertige Skriptsprache, die heute nur noch in ihrer Nische populär ist: Zeile für Zeile durch ihren Input durchzugehen und Dinge zu tun. Ich demonstriere:

# den alten Output aufräumen
clear

# NR > 1 -> Skippe die erste Zeile (die Überschriften)
# Dann assoziatives Array für jede Prio in dem wir die Summen sammeln.
# awk hat drei Segmente: BEGIN, dann der loop über die Zeilen dann END.
# Unser END-Segment gibt im for-Loop unsere Ergebnisse aus
awk -F, 'NR > 1 { summen[$4] += $2 * $3 } END { for (prio in summen) printf "Prio: %s, Summe: %.2f\n", prio, summen[prio] }' data.csv

Dann vielleicht noch eine nettere Darstellung von dem, was eigentlich gerade alles auf der Liste steht.

# sort ist besser im Sortieren, wir sortieren nach Prio aufsteigend, dann nach Preis absteigend, dann nach Name alphabetisch.
tail -n +2 data.csv | sort -t, -k4,4n -k3,3gr -k1,1d | awk -F, '{printf "%d, %d, %s, %.2f\n",$4,$2,$1,$3*$2}' | column -t -s,
# column baut uns eine hübsche Tabelle draus

Das schöne an diesem Vorgehen ist die Nähe zum Excel-Workflow. Wir können Daten und Formeln verändern und sehen unsere Ergebnisse in Echtzeit.

Das noch Schönere ist, dass wir nicht an die nervige Beschränkung von einzelnen Zellen gebunden sind. Wir können gemütlich auf mehreren Zeilen unsere Formeln schreiben und beliebig viele Kommandos ineinander pipe-n, ohne dass es unübersichtlich wird.

Wenn ich meine Daten an irgendjemanden weiterreichen möchte („Liebe Mayflower-Buchhaltung, hier sind Sachen die ich mega-super-duper-dringend für mein Projekt brauche …“), dann habe ich eine Welt von Tools, um mir CSV-Daten in jedes erdenkliche Darstellungsformat zu übersetzen.

pip install csvtomd
csvtomd ergebnis.csv > markdown-tabelle.md

… oder auch

csv2latex ergebnis.csv > latex-tabelle.tex

… oder auch

pip install csvkit
csv2html ergebnis.csv > html-tabelle.html

Mehr zu csvkit später in diesem Artikel.

Rollenspiel-Charaktere bauen

Ich spiele gerne Pen-&-Paper-RPGs, auch bekannt als Tabletop RPGs, auch bekannt als „Dungeons & Dragons und ach da gibt es noch andere Spiele?“.

Manche von diesen Systemen sind mechanisch so vielfältig, dass ich viele glückliche Stunden mit Spreadsheets verbracht habe, um diesen oder jenen Charakter zu bauen. Es ist vielleicht nicht das, wozu die meisten Leute Tabellenkalkulationsprogramme verwenden, aber es ist mit Abstand einer meiner Haupt-Anwendungsfälle.

Ich nehme Vampire: The Masquerade als Beispiel. Man spielt einen Vampir. Er hat (unter anderem) Punkte in Attributen und Fähigkeiten.

{
  "attributes": {
    "physical": {
      "strength": 2,
      "dexterity": 3,
      "stamina": 2
    },
    "social": {
      "charisma": 4,
      "manipulation": 3,
      "appearance": 3
    },
    "mental": {
      "perception": 2,
      "intelligence": 3,
      "wits": 2
    }
  },
  "abilities": {
    "talents": {
      "subterfuge": 3,
      "expression": 3,
      "empathy": 2,
      "leadership": 2
    },
    "skills": {
      "etiquette": 3,
      "performance (music)": 3,
      "stealth": 2
    },
    "knowledges": {
      "occult": 2,
      "politics": 2,
      "camarilla_lore": 2
    }
  }
}

Ich möchte jetzt (in einem Instant-Feedback-Setup wie oben) herausfinden, wie viele Punkte ich schon vergeben habe, wie viele ich noch vergeben darf und ob es irgendwelche Diskrepanzen gibt. Um es nicht zu kompliziert zu machen:

  • Attribute haben einen Startwert von 1 (außer natürlich Vampire des Clans Nosferatu, deren Fluch sie grauenvoll entstellt hat und die deshalb Appearance 0 haben, aber dieser Stat-Block ist ganz offensichtlich für einen Vampir vom Clan Toreador, weswegen diese Regel hier nicht greift) und teilen sich in drei Kategorien auf (Physisch, Sozial, Mental), auf die man 7, 5 und 3 Punkte verteilt
  • Fähigkeiten funktionieren ähnlich. Aufteilung in Talente, Fertigkeiten und Wissen mit Startwert 0 und 13, 9 und 5 Punkten.
read talents skills knowledges < <(jq '[.abilities.talents | add, .abilities.skills | add, .abilities.knowledges | add]' data.json | jq '.[]')
read physical social mental < <(jq '[.attributes.physical | add, .attributes.social | add, .attributes.mental | add]' data.json | jq '.[]')

echo <<EOT
Verteilte Punkte auf Attributen:
Physisch: $($physical-1)
Sozial: $($social-1)
Mental: $($mental-1)

EOT

if [[ $physical + $social + $mental -gt 18 ]]
then
  echo "ACHTUNG: Attributspunkte über dem Limit."
fi

echo <<EOT
Verteilte Punkte auf Fähigkeiten:
Talente: $talents
Fertigkeiten: $skills
Wissen: $knowledges

EOT

if [[ $talents + $skills + $knowledges -gt 27 ]]
then
  echo "ACHTUNG: Fähigkeitspunkte über dem Limit."
fi

Was wollte ich damit jetzt zeigen? Dass wir hier eine hübsche Schnittstelle haben, an der wir das volle Spektrum programmatischer Auswertung und Validierung zum Tragen kommen lassen können. Derselbe Algorithmus ließe sich genau so gut in ein Python-Skript füttern, das unter ähnlichen Bedingungen aufgerufen werden würde … komplett mit Live-Feedback!

Daten verstehen

Python ist ein guter Punkt. pandas, Jupyter und eine großzügige Prise R sind der Goldstandard der statistischen Auswertung. Manchmal will ich aber nicht meinen vollen Werkzeugkoffer aufmachen, wenn ich schnell ein bißchen Statistik aus einer Logdatei generiert habe. Manchmal möchte ich mit meinem Multitool ein paar schnelle Einblicke bekommen.

0, 0
1, 2
2, 4
3, 6
4, 8
5, 10

Nehmen wir mal an, dass wir eine CSV mit tausenden von Einträgen haben. Vielleicht schaue ich schnell mal rein:

less data.csv

… oder wenn das zu viele sind:

cat data.csv | wc -l

… vielleicht beschränke ich den Input ein wenig:

head -n 200 data.csv | less

Wenn ich zu viele Spalten habe, will ich vielleicht erstmal mit cut oder awk ein bißchen rumschnibbeln? Oder mit grep nach Sachen filtern, die interessant aussehen?

Vielleicht will ich schnell mal einen Graphen zeichnen:

cat data.csv| gnuplot -e "set terminal png; set output 'output.png';set size ratio -1;plot '-' with lines"

… oder einfach nur etwas über die Struktur der Daten erfahren:

csvstat data.csv

Moment. Da ist es ja wieder. So ein Programm aus csvkit.

Der Operationssaal für CSVs

Die Werkzeuge die ich bisher demonstriert habe sind universell einsetzbar, über eine große Bandbreite an unterschiedlich formatierten Textdateien. Die Beispiele die ich verwendet habe waren aber größtenteils CSVs. Also was hindert uns daran, spezialisierte Werkzeuge zu nehmen?

Gar nichts.

in2csv buchhaltung.xlsx > daten.csv

… wandelt Exceltabellen in CSV um.

csvgrep -c Typ -m "Ausgaben" data.csv | csvcut -c Datum, Summe, Zielkonto | csvsort -c Summe, Zielkonto | csvlook

Die Werkzeuge tun alle genau das was ihr Name vermuten lässt, kommen mit einer sportlichen Menge an dokumentierten Features und passen nahtlos ins Unix-Ökosystem. Ein besonderes Augenmerk auf:

csvsql --query "SELECT Zielkonto, COUNT(*) FROM daten GROUP BY Zielkonto" daten.csv

… und auf csvpy daten.csv, was die Daten gleich in eine Python Shell lädt.

Shell-Weisheit des Tages
Plaintext ist der König

Tools ändern sich ständig. Dinge in ein Tool einzupflegen bedeutet erstens, Arbeit zu investieren, und zweitens, Mauern aufzubauen. Ist Wissen wirklich verfügbar, wenn das Tool, in dem es drin ist, Flashplayer zum funktionieren braucht? Wird es dann auch weiter gepflegt?

Eine Reihe von Anpassungen in tausenden von Word-Dokumenten zu machen ist ein Job für mehrere Leute über den Lauf einer Woche. Eine Reihe von Anpassungen in tausenden Textdateien zu machen ist eine Aufgabe für eine*n Programmierer*in für vielleicht zwei Stunden. Dazu braucht es dann auch kein Sharepoint; Git wurde genau zu diesem Zweck entwickelt.

Plaintext mag nicht so hübsch aussehen, aber es lässt sich in jedes Format hineingießen. Plaintext kann eine Webseite werden, ein PDF, ein gedrucktes Buch. Ich kann Plaintext auf einem iPad Pro schreiben oder auf einem Atari ST 1040 und für die Endnutzer wird es keinen Unterschied machen.

Ein gutes Video zu diesem Thema ist The Unreasonable Effectiveness of Plaintext.

Mein Punkt ist jener: Plaintext mag die Vergangenheit sein, aber es ist auch die Zukunft. In dem Moment, in dem wir uns von spezifischen Tools lösen – und sei es nur auf einer persönlichen Ebene im Rahmen einer Notizsammlung – haben wir plötzlich alle Tools zur Verfügung.

Avatar von Eric

Kommentare

Eine Antwort zu „CLI-Adventskalender: Tabellenkalkulation“

  1. […] Kommandozeilen-Tabellenkalkulation. Siehe Artikel vom 10.12. […]

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.