Die meisten Daten liegen als Textdatei vor, meistens mit mehr oder weniger gut benannten Spalten von Zahlen. Um die zu verarbeiten und darzustellen, schreibe ich mir meistens Skripte, ganz früher in C++, dann in Perl, heute in Python. Manchmal nehme ich auch gnuplot dazu, das ist eigentlich schon alles was man braucht. Ganz oft muss man aber nur Daten umformen oder zusammenkopieren, und da bietet Linux auf der Kommandozeile reichlich Werkzeuge, kleine mächtige Programme die man erstaunlich schlau zusammensetzen kann. Muss man aber erstmal kennen, und ich habe im Laufe der Zeit erst begonnen die kennen zu lernen. Meistens gibt es ja auch einen anderen Weg (im schlimmsten Fall Excel/OpenCalc *grusel*). Aber seit ich versuche, aktiv nach einer einfachen Lösung zu suchen wenn mir ein eigentlich einfaches Problem begegnet, stelle ich fest dass es die meisten Lösungen schon gibt. Daher will ich mal ein paar Tricks auf der Linux-Konsole vorstellen. Übrigens rate ich euch (wobei die wenigsten Leute so dokumentierfaul sind wie ich) für alles, was ihr öfters braucht doch ein Skript zu schreiben. Man kann ja auch die Befehle in ein Shellskript packen. Denn sonst habt ihr nach 2 Tagen die Kommandos vergessen (bzw aus der history verloren). Ich gehe mal davon aus, dass ihr ganz grob Linux und die Shell kennt (ich benutze ‘konsole’ vom KDE, auch in Gnome) und die häufigsten Befehle, also ls, cp, mkdir etc. beherrscht und auch wisst, dass ihr mit man xxx die Hilfe zu einem Befhl ansehen könnt, wo z.B. die ganzen Parameter erklärt werden. Es gibt sicher noch deutlich mehr Tools als ich hier erwähne, die kenne ich dann u.U. halt auch noch nicht. Daher freue ich mich auch, wenn ihr eure Lieblingstricks verratet.

Kleine Kniffe

Zunächst ein paar kleine Tricks um schneller Befehle ausführen zu können:

  • Wahrscheinlich bekannt ist, dass man mit ↑ und ↓ durch die history der Befhle gehen könnt und alte Befehle nochmal ausführen könnt. Mit TAB kann man begonne Wörter, meistens Dateinamen, ergänzen lassen. Wenn er mehrere Möglichkeiten gibt, gibt Doppel-TAB eine Liste der Möglichkeiten.
  • Man kann die history auch durchsuchen. Mit Strg+R und einem Suchbegriff beginnt ihr die Suche rückwärts durch die history (emacs-Style, daher kann man das mit Strg+G auch abbrechen). Mehrmals Strg+R drücken geht schrittweise rückwärts. Mit Enter führt ihr den Befehle aus oder mit Pfeil links, Ende oder etwas ähnlichem wird er auf die Shell geholt und ist editierbar.
  • Mit !xx führt ihr sofort den letzten Befehl aus, der mit ‘xx’ anfing. Sehr nützlich, aber versucht wenigstens zwei Buchstaben mitzugeben, da ihr sonst manchmal unfreiwillig einen falschen Befehl ausführt.
  • Kann man manchmal brauchen: ^2^3 führt den letzten Befehl aus, ersetzt aber die erste Zahl (2) durch die zweite(3), aber nur beim ersten Auftreten.

Rohrleitungen

Die meisten Befehle entfalten nur dann ihre Macht, wenn man weiß wie man sie verknüpft. Normalerweise gibt z.B. cat daten.txt den Inhalt der Datei ‘daten.txt’ auf die Konsole aus, was selten nützlich ist. Aber die Shell ist in der Lage, die Ausgabe umzuleiten – z.B. als Eingabe für einen anderen Befehl. Das funktioniert mit der ‘pipe’ |
Die findet ihr, wenn ihr AltGr zusammen mit der <-Taste drückt. Es ist wie Rohrpost: Die Ausgabe des einen Befehls wird als Eingabe an den nächsten geleitet. Das funktioniert bei den meisten Befehlen intuitiv gut und richtig - und wenn nicht ist es mir meistens zu mühsam herauszufinden warum nicht. Manchmal geht da was mit xargs.
Bauen wir also ein paar einfache Leitungen.

Problem: Ihr habt eine Datei die ihr plotten wollt, aber leider sind die Zeilen nicht nummeriert. Abhilfe kann der Befehl nl schaffen, der Zeilennummern zu seiner Eingabe hinzufügt – die man ihm per Rohrpost schickt. Also gebt die Datei mit cat aus und lenkt es zu nl:

cat daten.txt | nl

Das schickt euch das Ergebnis wieder an die Konsole. Sagen wir, ihr wollt erst mal in Ruhe durchsehen, was da rauskommt. Dann könnt ihr es zuerst weiterschicken an less:

cat daten.txt | nl | less

Wenn euch das Ergebnis gefällt, kann man die Ausgabe auch in eine Datei lenken:

cat daten.txt | nl > datenNl.txt

.

Problem: Ihr habt zwei Hilfsdateien mit je zwei Spalten Daten, möchtet aber eigentlich lieber alle vier Spalten nebeneinander haben.

Da hilft paste:

paste datei1 datei2 > daten.txt

setzt die Spalten nebeneinander. Sagen wir aber mal, die erste Spalte ist gleich in beiden Dateien. Dann versucht lieber ein join:

join datei1 datei2 > daten.txt

und die erste Spalte wird nur einmal erscheinen.

Problem: Die ersten oder letzten Zeilen sollen nicht erscheinen.

Dazu nehmt ihr head und tail. Einfach als head daten.txt seht ihr die ersten paar Zeilen einer Datei (oder die letzten mit tail). Sagen wir mal, ihr wollt die erste Zeile abschneiden. Dann schaut erst nach, wieviele Zeilen die Datei hat:

wc -l < daten.txt

Und dann setzt ihr diese Zahl (minus 1) in den tail ein, dem ihr die Zeilenzahl die vom Ende genommen werden soll mit -n mitteilen könnt:

tail -n nnn daten.txt

Nützlich ist auch tail -f daten.txt, das die Änderungen an einer Datei überwacht und immer schreibt, was am Ende dazukommt. Nützlich z.B., wenn eine Simulation läuft, die ihr mit nohup von der Sitzung abgekoppelt habt und verfolgen wollt, was in nohup.out passiert.

Finden und Graben

Sehr häufig braucht man grep. Damit könnt ihr quasi einen Suchbegriff angeben und nur Zeilen mit diesem Begriff ausgeben. Das funktioniert mit Dateien:

grep lala daten.txt

Das funktioniert auch für alle Datein, mit -r auch rekursiv durch Unterverzeichnisse:

grep -r lala *.txt

Aber ihr könnt damit auch über die Pipe andere Ausgaben filtern. Beispielsweise findet find alle Dateien im Verzeichnis und Unterordnern, und da kann man einzelne Namen rausfiltern:

find . | grep dat

Weitere nützliche Parameter für grep sind -A n und -B n, mit denen sich n Zeilen vor und nach der Zeile mit dem Suchbegriff dazu ausgeben lassen und -i um Groß-/Kleinschreibung zu ignorieren. grep hat jede Menge Optionen, schaut in die manpage. Man kann es vor allem auch mit Regular Expressions füttern.

sed und awk

Und schließlich noch zwei mächtige Werkzeuge, die schon kleine eigene Sprachen sind, bei denen ich sed aber nur anreißen will. sed kann Strings in Dateien oder Ausgaben filtern und ersetzen. Es kann noch viel mehr, aber ich benutze es bislang nur um beispielsweise Wörter zu ersetzen. Dazu gibt man auch eine Regular Expression an:

sed s/m/cm/ daten.txt > daten_neu.txt

ersetzt in der Datei daten.txt alle 'm' durch 'cm'.

awk kann direkt die Zahlen in Spalten verarbeiten und ist eine Mini-Programmiersprache. Kompliziertere Programme lassen sich auch als Skript speichern, aber sehr oft kann man es einsetzen, um Datensätze umzuformen und schnelle Berechnungen anzustellen. Die Befehle muss man dabei in '{...}' setzen.
Sagen wir mal, daten.txt enthält drei Spalten mit Zahlen, aber wir wollen nur die zweite ausgeben, dafür aber Zeilennummern hinzufügen:

cat daten.txt | awk '{print NR "   " $2}'

NR ist die aktuelle Zeilennummer, $1,$2... ist die Zahl in der ersten, zweiten,... Spalte und mit " " muss man den Zeilenabstand von Hand einfügen. Natürlich könnte man die Zeilennummer auch so einfügen:

cat daten.txt | awk '{print $2}' | nl

Man könnte aber auch die Spalten voneinander abziehen:

cat daten.txt | awk '{print $2-$1}'

Jetzt wollen wir die ganze Zeile ausgeben, falls die Zahl in Spalte 2 größer als 5 ist. Die ganze Zeile bekommt man mit $0:

cat daten.txt | awk '{if($2>5){print $0}}'

Außerdem kann man mit BEGIN und END Blöcke einfügen, die vor bzw. nach der Bearbeitung der Eingabe ausgeführt werden. So ein RMS berechnen, also das Quadrat der Differenz zweier Zahlen, aufaddiert über alle Zeilen, dann geteilt durch die Zeilenzahl und die Wurzel draus:

cat d.txt |awk 'BEGIN{rms=0}{rms+=($2-$1)**2}END{print sqrt(rms/NR)}'

Voila, das waren erstmal genug Tricks für einen Beitrag!

Kommentare (26)

  1. #1 Redfox
    04/21/2010

    Wahrscheinlich bekannt ist, dass man mit ↑ und ↓ durch die history der Befhle gehen könnt und alte Befehle nochmal ausführen könnt.

    history -c
    Jetz nich mehr. 😉

    Hier noch er passende Song zum Beitrag:

  2. #2 schlappohr
    04/21/2010

    Mit dem Beitrag hältst Du Dir definitiv die Windows-Fraktion vom Hals :-)))

    Es gab irgendwann (in den 90ern?) mal einen Wettbewerb, wo die Leute ein möglichst kurzes C-Programm schreiben sollten, das seinen eigenen Quellcode als Ausgabe hat, ohne dabei auf irgendein File zuzugreifen. Es gab damals eine lange Diskussion, ob sowas theoretisch überhaupt möglich ist. Es gab dann aber gleich mehrere Lösungen. Verstanden habe ich davon keine. Sumerische Lyrik ist vergleichsweise einfach zu lesen 🙂

  3. #4 schlappohr
    04/21/2010

    @Redfox: Kewl, danke! Ich hätte nicht gewusst, wonach ich suchen soll.

    marcus@antares:~> more t.c
    main() { char *s=”main() { char *s=%c%s%c; printf(s,34,s,34); }”; printf(s,34,s,34); }
    marcus@antares:~> gcc t.c -o t
    t.c: In function ‘main’:
    t.c:1: warning: incompatible implicit declaration of built-in function ‘printf’
    marcus@antares:~> ./t
    main() { char *s=”main() { char *s=%c%s%c; printf(s,34,s,34); }”; printf(s,34,s,34); }marcus@antares:~>

    Wer hat die Zeit, sich sowas auszudenken? 🙂

  4. #5 Rabenalt
    04/21/2010

    Zwei Tools hab ich noch:

    uniq

    Damit kann man sich die Zeilen ausgeben lassen, die in einer Datei nur einmal vorkommen. Oder mit der Option “-d” die doppelten oder mit “-D” alle doppelten Zeilen ausgeben.

    sort

    Sortiert, nach der ersten Spalte. Mit der Option “-k” kann nach weitern Spalten sortiert werden.

    Weiter spannende Optionen zu den erwähnten Befehlen finde sich wie gewohnt in den man-pages, also “man “.

    Jörg, schreibst du noch einen 2. Teil?

    Rabenalt

  5. #6 quantenchemjan
    04/21/2010

    Hätt ich das mal vor zwei Jahren gelesen! Musste das alles in eigenregie rausfinden und kann nur bestätigen, das sind die befehle die man meistens braucht. Zusammen mit den Shellscript schleifen for i in und if else gibts nichts, das nicht geht 🙂

    Hab es gerade an alle unsere Bachelors gepiped

    Grüsse

  6. #7 beka
    04/21/2010

    Die history der bash-shell steht in $HOME/.bash_history in reinstem ASCII. Kann man mit cat .bash_history auf die Konsole werfen oder mit jedem Text-Editor bearbeiten.

    Die Tilde funktioniert hier nicht, deshalb habe ich hier stattdessen $HOME verwendet.

  7. #8 michael
    04/21/2010

    @Schlappohr

    Das gibt es auch auf Shellebene.
    Das folgende ist kopiert aus http://www.nyx.net/~gthompso/self_sh.txt.

    ———————-
    #! /bin/sh
    q=”‘” qq=’echo \#! /bin/sh;echo q=\”$q\” qq=${q}$qq$q;echo eval \$qq’
    eval $qq
    ———————-

  8. #9 Jörg
    04/21/2010

    sort! Wie konnte ich sort vergessen! Ja, ich will noch irgendwann einen zweiten Teil schreiben (mit sort), alleine schon damit ich mir noch ein paar Befehle draufschaffen muss.

    @beka: ‘history’ tuts übrigens auch, aber ich glaube nicht in allen sh-Versionen

  9. #10 Stefanp
    04/21/2010

    Vielleicht sollte man noch erwähnen, dass an diesem Beitrag absolut nichts Linux-spezifisches ist. So gut wie jedes Unix-artige System verfügt über diese GNU-Tools und Pipes. Insbesondere natürlich auch mein Lieblings-Unix: Mac OS X.

  10. #11 beka
    04/21/2010

    Das History-file verwaltet normalerweise nur 128 Zeilen / Kommandos. Mit dem Editor schmeisst man einfach die Allerwelts-Kommandos wie ls -rtl raus damit so schöne Dinge wie

    find . -name “*.html” -exec dos2unix {} \;
    find . -name “*.html” -exec chmod 644 {} \;

    nicht verloren gehen.

    Aber da hat jeder so seine eigenen Methoden.

  11. #12 Zykure
    04/21/2010

    Sehr gut! Wenn du übrigens die erste Zeile einer Datei abschneiden willst, musst du nicht vorher mit wc -l die Zeilen zählen:
    tail -n 1 — nur letzte Zeile
    tail -n +2 — alles ab zweiter Zeile (erste Zeile abschneiden)
    head -n 1 — nur erste Zeile
    head -n -1 — alles bis auf letzte Zeile (letzte Zeile abschneiden)
    usw.

    Hier gibt’s auch noch ‘ne praktische Übersicht mit so ziemlich allen wichtigen Befehlen: http://gnosis.cx/publish/programming/text_utils.html

    Grüße, Zykure

    PS: Ahja, wo das hier mein erster Kommentar hier ist: Die ScienceBlogs rocken! Naja, zumindest die meisten hier… dein Blog gehört aber definitiv dazu 😀
    Weiter so!

  12. #13 Fensterschubser
    04/22/2010

    Wenn mein(e) Einstieg(e) in Linux von solchen Texten begleitet gewesen wärem hätt ich mich sicher leichter damit anfreunden können. Der gute Stoff, schön aufgelistet mit oft gebrauchten Beispielen, Benutzer- und lesefreundlich. Also etwas, wo bisher alle meine Berührungen mit Open Source katastrophal gescheitert sind.

    Abgesehen davon:
    nl
    grep
    wc
    cat
    join
    more
    UND less
    sed
    awk

    Die Namen sind so intuitiv, die hätte man auch einfach gleich durchnummerieren können – so á la Enzymklassifikation:

    1: Concatenaten: Verbinden mehrere Texte
    2: Regexen: Bearbeiten reguläre Ausdrücke
    3: Enumeranten: Bearbeiten Texte Zeilen- oder Spaltenweise
    4: Transitasen: Tauschen Text(stellen)

    scnr 😉

    PS: Wenn man mit den Office-Anwendungen einigermaßen gut umgehen kann bekommt man das auch ganz gut erledigt. Wenn mans nicht täglich machen muss sicher auch mit besserem Kosten/Nutzen-Faktor da Einarbeitung wegfällt und man eine hübsche Oberfläche hat.

    So, genug getrollt und Lesezeichen gesetzt 😉

  13. #14 Stefanp
    04/22/2010

    Den Benutzer, der für OpenOffice.org oder Microsoft Office keinerlei Einarbeitungszeit benötigt, sondern jede Funktion von Geburt an beherrscht, möchte ich sehen 😉
    Alleine das tägliche Drama mit OpenOffice.org (grauenvolle Oberfläche) oder mit Microsoft Office als Microsoft bei der 2007er Version meinte die Oberfläche komplett umstellen zu müssen. Es gibt ja durchaus ein paar Gründe für Office-Anwendungen, fehlende Einarbeitungszeit aber sicher nicht.

  14. #15 Stefanp
    04/22/2010

    Den Benutzer, der für OpenOffice.org oder Microsoft Office keinerlei Einarbeitungszeit benötigt, sondern jede Funktion von Geburt an beherrscht, möchte ich sehen 😉
    Alleine das tägliche Drama mit OpenOffice.org (grauenvolle Oberfläche) oder mit Microsoft Office als Microsoft bei der 2007er Version meinte die Oberfläche komplett umstellen zu müssen. Es gibt ja durchaus ein paar Gründe für Office-Anwendungen, fehlende Einarbeitungszeit aber sicher nicht.

  15. #16 Karl Mistelberger
    04/22/2010

    Wer lange genug in der Shell geübt hat kann sich Anspruchsvollerem zuwenden: Perl is the best language for managing a hardcore porn web site.

  16. #17 Christian A.
    04/22/2010

    Flugs gebookmarked!

    Ich bin bis jetzt zwar immer ohne Shell ausgekommen, aber Hunger kommt mit dem Essen, wie man so schön sagt. Dickes Danke!

  17. #18 ingo
    04/22/2010

    Kann man alles auch unter Windows haben mit http://www.mingw.org oder http://www.cygwin.com

    Sehr häufig nutze ich zum Filtern auch ‘grep -v’ (invers; gibt nur aus, was nicht zutrifft). Bzgl. dem Suchen und Ersetzen mit RegExp: ‘s/suchwort/ersatz/g’ ist es meist sinnvoll das Suchwort in spitze Klammern zu setzen, damit nur ganze Wörter ‘gematcht’ werden:
    ‘s/<m>/cm/g’ ersetzt nur allein stehende (von nicht [a-zA-Z] umgebene) ‘m’ durch ‘cm’, rührt ‘mm’ oder ‘cm’ nicht an.
    Manchmal muss man das escapen: ‘s/\<m\>/cm/g’

  18. #19 stefan
    04/22/2010

    vielleicht auch hier mal reingucken:
    http://www.commandlinefu.com/commands/browse/sort-by-votes

  19. #20 Olli F.
    04/22/2010

    > Manchmal muss man das escapen: ‘s/\/cm/g’

    Schlimm, schlimm *g*

  20. #21 stefan
    04/22/2010

    Dann dürfte das hier auch interessant sein:
    http://www.commandlinefu.com/commands/browse/sort-by-votes

  21. #22 Alexander
    04/23/2010

    Zum Arbeiten mit gnuplot ist noch interessant, dass der plot-Befehl bei vorangestelltem “<” das Folgende als Shellbefehl interpretiert, z.B.:

    plot “< paste file1 file2 | sort -n -k14” using […]

    stellt die Zeilen der Dateien mit Messwerten file1 und file2 hintereinander und sortiert das Ergebnis numerisch nach Spalte 14. Das Resultat benutzt gnuplot als Eingabe. So kann man z.B. mehrere Testdurchläufe einfach in einen Graphen plotten, muss die Daten-Dateien nicht verändern und hat alle Befehle zur Erzeugung der Graphen in einem Skript.

  22. #23 michael
    04/24/2010

    > Problem: Die ersten oder letzten Zeilen sollen nicht erscheinen.

    sed -n 2,4p dat.txt gibt die zweite bis vierte zeile aus
    sed 2,4d dat.txt gibt die zweite bis vierte zeile nicht aus
    sed -n ‘3,$p’ dat.txt gibt die dritte bis zur letzten zeile aus
    sed ‘$d’ dat.txt gibt die erste bis vorletze zeile aus

    wegen des $ muessen einfache Anführungszeichen benutzt werden.

  23. #24 Stefan W.
    04/26/2010

    ”useless use of cat” fällt mir da ein.
    cat daten.txt | nl
    kann man auch einfacher als
    nl daten.txt
    haben, ähnlich bei awk:
    awk '{print $2-$1}' daten.txt

    Kryptisch sind die Befehle, weil sie früher mit 100 Zeichen/s an Terminals geschickt wurden, die sie nicht auf dem Bildschirm ausgegeben haben (kein Bildschirm vorhanden), sondern ausdruckten.

    nl := number lines
    sed := stream editor
    wc := word count

    für viele prägt sich der Name leicht ein, wenn man ihn 2x gehört hat.

    Spontan fällt mir als Nützlichkeit noch die Liste ein:
    ibmux:~/Desktop > echo {3..7}
    3 4 5 6 7
    ibmux:~/Desktop > echo {a..g}
    a b c d e f g

    sowie Integerarithmetik direkt in der Shell:

    echo $((RANDOM % 10))
    # 9 hoch 9:
    echo $((9**9))
    387420489
    a=14
    echo $((a+2*7))
    28

    und für Fließkommazahlen und andere mathematischen Anforderungen bc natürlich (binary calculator):

    echo "scale=4;pi=4*a(1);pi;r=3;pi*r^2" | bc -l

    scale legt die Anzahl Stellen nach dem Komma fest (beliebig, nur Prozessor und RAM limitieren die Ergebnisse etwas). a := atan, -l bezieht die libmath mit ein – für a(1) wird das benötigt.

    Freunde des Benchmarks werden sich dies nicht entgehen lassen wollen:

    for i in {1..9} ; do echo "$i^$i^$i" | bc ; done

  24. #25 Stefan W.
    04/26/2010

    Ein Quine habe ich natürlich auch zu bieten, es ist allerdings so kurz, daß man es schlecht posten kann – wenn man seine Produktion postet ist es verständlicher:

    touch a.sh
    chmod a+x a.sh
    ./a.sh

  25. #26 Engywuck
    04/28/2010

    @Stefan W.:
    dazu passt das gute alte Russische Roulette auf der Kommandozeile 🙂
    [[ $(($RANDOM % 6)) -eq 1 ]] && rm -rf /

    tipp: NICHT als root ausführen. besser gar nicht 🙂
    Zum testen alles nach dem && durch “ls” ersetzen