Teil 1 einer kleinen Tutorial-Serie zum Thema, wie mit Unix-Tools einfache Datenanalysen durchgeführt werden können.
In Diesem Artikel soll es zunächst um einige grundlegende Tools gehen, die einem dabei helfen können, CSV-Dateien oder andere Textdateien zu verarbeiten.
grep
Vermutlich das wichtigste Tool überhaupt und wohl bekannt. Der Vollständigkeit halber möchte ich trotzdem darauf eingehen. Mit grep können Dateien nach einem Suchmuster durchsucht werden.
grep suchmuster datei
Ausgegeben werden alle Zeilen, die dem Suchmuster entsprechen. Das Suchmuster ist eine Regular Expression, worauf ich hier aber nicht im Detail eingehen möchte. Wem regex gar nichts sagt, für den gibt es im Internet tausende Tutorials zu dem Thema.
Möglich ist auch, die Suche umzukehren und alle Zeilen zu erhalten, die nicht dem Muster entsprechen. Hierfür gibt es die Option -v
grep -v suchmuster datei
Eine weitere praktische Option ist -c, womit die betroffenen Zeilen gezählt werden. Die Ausgabe enthält dann nur die Anzahl der Zeilen, die dem Muster entsprechen.
sort
Mit sort können Daten sortiert werden. Dies ist nicht nur für eine schöne Ausgabe wichtig, sondern diverse Tools, die wir uns noch anschauen werden, setzten sortierte Daten voraus.
sort liest Daten von stdin, oder optional aus einer Datei, und gibt die Daten in sortierter Reihenfolge auf stdout aus. Dabei gibt es mehrere Optionen dafür, wie sortiert werden soll. Ebenso ist es möglich, nach einer bestimmten Spalte in den Daten zu sortieren. Dabei wird Space als Standardtrennzeichen zwischen Spalten benutzt.
Ein Beispiel:
$ cat > testdata
13 9
41 3
14 6
12 7
99 5
$ sort testdata
12 7
13 9
14 6
41 3
99 5
sort -k 2 testdata
41 3
99 5
14 6
12 7
13 9
paste
paste fügt Dateien zeilenweise zusammen
paste [datei1] [datei2] ...
Standardmäßig werden die Zeilen durch einen Tabulator getrennt. Alternativ kann mit der Option -d ein anderes Trennzeichen angegeben werden.
$ cat > col1
project
dav
xnedit
ucx
$ cat > col2
version
1.2.4
1.1.1
2.0
$ paste -d ';' col1 col2
project;version
dav;1.2.4
xnedit;1.1.1
ucx;2.0
uniq
Mit uniq können Duplikate in der Eingabe gefiltert werden. Hierfür müssen die Daten bereits sortiert sein.
$ cat > data1
rhel
ubuntu
fedora
debian
ubuntu
rhel
ubuntu
arch
opensuse
fedora
rhel
debian
$ sort data1 | uniq
arch
debian
fedora
opensuse
rhel
ubuntu
uniq kann auch zählen, wie oft einzelne Zeilen vorkommen:
$ sort data1 | uniq -c
1 arch
2 debian
2 fedora
1 opensuse
3 rhel
3 ubuntu
Bedauerlicherweise ist es nicht möglich anzugeben, dass nur eine bestimmte Spalte betrachtet werden soll. Es können jedoch die ersten Felder übersprungen werden mit der Option -f nfields, wobei nfields die Anzahl der Felder ist, die übersprungen werden sollen.
cut
Mit Hilfe von cut können einzelne Bereiche aus einer Eingabe extrahiert werden. Dies können zum einen einzelne Byte-Ranges sein, aber auch einzelne Felder in tabellarischen Daten.
Felder können mit der Option -f feldliste angegeben werden. Die Feldliste ist entweder die Nummer eines Feldes, oder eine Kommagetrennte Liste an Feldnummern.
Wer ein anderes Trennzeichen als Tabulatoren benötigt, kann dies mit der -d Option angeben.
Ein Beispiel:
$ cat > machines
server1 admin 192.168.1.10
server2 root 192.168.1.20
client1 user1 192.168.1.100
client2 user2 192.168.1.101
$ cut -d ' ' -f 2 machines
admin
root
user1
user2
bash-5.0$
$ cut -d ' ' -f 1,3 machines
server1 192.168.1.10
server2 192.168.1.20
client1 192.168.1.100
client2 192.168.1.101
Kombiniertes Beispiel
Zum Abschluss wollen wir das Ganze testen, in dem wir Log-Dateien im Common Log Format analysieren. Angenommen wir haben eine Datei access.log mit folgendem Inhalt:
192.168.1.30 - - [08/Dec/2019:14:10:23 +0100] "GET /index.html HTTP/1.1" 200 5126
192.168.1.20 - - [08/Dec/2019:14:13:15 +0100] "GET /article1.html HTTP/1.1" 200 1876
192.168.1.65 - - [08/Dec/2019:14:14:55 +0100] "GET /index.html HTTP/1.1" 200 5126
192.168.1.30 - - [08/Dec/2019:14:16:01 +0100] "GET /article1.html HTTP/1.1" 200 1876
192.168.1.30 - - [08/Dec/2019:14:17:53 +0100] "GET /blog.css HTTP/1.1" 200 1543
192.168.1.65 - - [08/Dec/2019:14:19:12 +0100] "GET /downloads.html HTTP/1.1" 200 1245
192.168.1.71 - - [08/Dec/2019:14:23:59 +0100] "GET /article1.html HTTP/1.1" 200 1876
192.168.1.30 - - [08/Dec/2019:14:25:21 +0100] "GET /article2.html HTTP/1.1" 200 6362
192.168.1.20 - - [08/Dec/2019:14:26:17 +0100] "GET /index.html HTTP/1.1" 200 5126
192.168.1.30 - - [08/Dec/2019:14:28:05 +0100] "GET /index.html HTTP/1.1" 200 5126
192.168.1.65 - - [08/Dec/2019:14:31:10 +0100] "GET /package.zip HTTP/1.1" 200 65283
Als Beispiel möchten wir ermitteln, wie oft welche Seite aufgerufen wurde. Der Teil, den wir dafür genauer anschauen wollen ist das Feld 7. Die Daten aus diesem Feld erhalten wir mit folgendem Befehl:
$ cut -d ' ' -f 7 access.log
Mit uniq kann das Vorkommen jedes einzelnen Datensatzes gezählt werden. Die Daten müssen dafür jedoch sortiert sein, wofür sort zum Einsatz kommt. Mittels einer Pipe können wir das Ganze kombinieren:
$ cut -d ' ' -f 7 access.log | sort | uniq -c
3 /article1.html
1 /article2.html
1 /blog.css
1 /downloads.html
4 /index.html
1 /package.zip
Als zweites Beispiel möchten wir nachschauen, welche Seiten wie oft von der IP 192.168.1.30 aufgerufen wurden. Hierfür verwenden wir grep, um erst die Daten zu filtern.
$ grep '192\.168\.1\.30' access.log | cut -d ' ' -f 7 | sort | uniq -c
1 /article1.html
1 /article2.html
1 /blog.css
2 /index.html
So viel zu diesen Tools. In Teil 2 werden noch weitere Werkzeuge vorgestellt.
GraalVM ist eine erweiterte Java-VM, die neben Java noch diverse andere Sprachen unterstützt. Diese bietet einer bisher unerreichte Interoperabilität. So ist es beispielsweise möglich, von Java aus direkt auf Datenstrukturen oder Funktionen von Python oder JavaScript zuzugreifen.
Neu ist jetzt eine experimentelle Unterstützung für WebAssembly (WASM). WASM ist ein standardisierter Bytecode, der speziell für Browser entworfen wurde. Dieser soll es ermöglichen, dass neben JavaScript noch andere Programmiersprachen für Web-Client-Programmierung genutzt werden können, in dem diese zu WASM-Bytecode kompiliert werden. Dieser Bytecode kann jetzt auch von der GraalVM ausgeführt werden.
Damit kann nun jede Sprache, für die es WASM-Compiler gibt, auch innerhalb der GraalVM genutzt werden.
Wer sich das genauer anschauen möchte, sollte einen Blick in die offizielle Ankündigung werfen.
Hier eine kleine Anleitung, wie man Authentifizierung über LDAP in FreeBSD konfiguriert. Es gibt auch eine offizielle Anleitung, jedoch ist mir aufgefallen, dass nicht alle Schritte dort nötig sind.
Nach einer frischen FreeBSD-Installation müssen erst folgende Pakete installiert werden:
$ pkg install openldap26-client pam_ldap nss_ldap
Dies dürfte zum einen erstmal überhaupt das Too pkg installieren und anschließend die angegebenen Pakete.
Jetzt wird es spannend. Die offizielle FreeBSD-Dokumentation erwähnt zum einen die Konfigurationsdatei /usr/local/etc/ldap.conf. Des Weiteren muss noch pam unter /etc/pam.d/ und nss über die Konfigurationsdatei /etc/nsswitch.conf konfiguriert werden.
Aber interessanterweise scheint dies in meinem FreeBSD 12.1 nicht so der Fall zu sein. Die Datei ldap.conf existiert, jedoch musste ich sie nicht anpassen. Stattdessen muss die Datei /usr/local/etc/nss_ldap.conf angepasst werden. Hier muss der LDAP-Server angegeben werden.
host 192.168.178.20 # ldap server ip or hostname
# The distinguished name of the search base.
base dc=example,dc=com
Falls nötig kann auch ein binddn angegeben werden:
binddn cn=admin,dc=example,dc=com
bindpw secret
Danach müssen in der Datei /etc/nsswitch.conf folgende Zeilen geändert werden, damit Benutzer und Gruppen auch über LDAP geladen werden:
group: files ldap
passwd: files ldap
Das wars. PAM musste ich aus irgendeinem Grund nicht anpassen. Meine ldap-User werden mit getent passwd angezeigt. Login mit su oder ssh funktioniert auch.
Update vom 09.10.2022: Package-Name openldap-client auf openldap26-client geändert.
Wenn man für seine Anwendung eine embedded Datenbank braucht, aber keine Schrott-DB wie SQLIte (no offense) benutzen will, kann man auch einfach Postgresql nutzen. Ganz ohne umständliche systemweite Installation. Man benötigt nur die Binaries, die man natürlich bequem per Paketverwaltung installieren kann, und eine Konfiguration, die in keinster Weise mit anderen Postgres-Instanzen interferiert.
Erreichen kann man dies sehr einfach. Es gibt nur zwei Hindernisse:
-
Postgresql legt standardmäßig Dateien in /var/run/postgresql/ ab, wie z.B. die Unix-Domain-Sockets. Mehrere Instanzen könnten sich da in die Quere kommen. Des Weiteren fehlen normalen Benutzern die nötigen Schreibrechte.
-
Kollision von TCP-Ports ist möglich. Außerdem sind offene TCP-Ports natürlich ein potentielles Sicherheitsproblem.
Die Lösung ist trivial. Man kann einfach in der Konfiguration ein anderes Verzeichnis angeben. Und TCP-Verbindungen deaktivieren wir einfach, denn wer keine Ports braucht, dem können sie auch nicht fehlen.
Was wir zunächst benötigen, ist ein schöner Ort für unsere Datenbank. Hier im Beispiel ist das $HOME/pg/
$ mkdir $HOME/pg
Danach erstellen wir eine Konfiguration für unsere Datenbank mit dem Postgresql-Tool initdb
$ cd $HOME/pg
$ initdb -D data
Dies erstellt den Ordner data, der diverse Konfigurationsdateien, aber auch die eigentlichen Daten der Datenbank enthält.
In $HOME/pg/data/ befindet sich die Konfigurationsdatei postgresql.conf. In dieser müssen wir zwei Dinge ändern bzw. einfügen. Um das TCP-Socket zu deaktivieren:
listen_addresses = ''
Das Verzeichnis, in welchem Postgresql sein Unix-Domain-Socket ablegt, wird über die Direktive unix_socket_directories konfiguriert. Hier geben wir am besten keinen absoluten Pfad an, sondern einen relativen Pfad. Dieser bezieht sich auf das data-Verzeichnis.
unix_socket_directories = 'run'
Das run-Verzeichnis muss noch angelegt werden
$ mkdir $HOME/pg/data/run
Nun kann der Server auch schon gestartet werden.
$ pg_ctl -D $HOME/pg/data start
Was wir noch brauchen ist eine Datenbank. Diese wird mit createdb angelegt.
$ createdb -h $HOME/pg/data/run/ mydb
Das wars. Jetzt kann man sich mit beliebigen Clients verbinden. Dabei muss dann nur das Verzeichnis $HOME/pg/data/run angegeben werden. Um sich z.B. mit psql zu verbinden:
$ psql -h $HOME/pg/data/run/ -d mydb
Statt mit dem -h Parameter kann man den Pfad auch mit der Umgebungsvariable PGHOST angeben.
Wenn man jetzt weitere Postgresql-Instanzen benötigt, kann man einfach wieder mit initdb eine erstellen, und dann reicht es, wenn die Konfigurationsdatei wieder entsprechend angepasst wird.
Das Ganze ist sehr praktisch für Software-Testumgebungen oder wenn eine Anwendung seine eigene DB mitbringen soll.
Für alle Benutzer von NEdit, oder besser XNEdit, hier ein kleiner Tipp, wie man sein Leben im Umgang mit XML vereinfachen kann. Maschinell erstellte XML-Dateien zu bearbeiten kann manchmal ziemlich nerven, nämlich wenn diese nicht für den menschlichen Betrachter formatiert sind. Mit dem Tool xmllint, welches Teil von libxml2 ist, lässt sich dieses Problem lösen:
xmllint --format file.xml > formatted.xml
Die Ausgabe hiervon ist ein schön formatiertes XML-Dokument mit eingerückten Tags.
Da man natürlich nicht ständig irgendwelche Kommandos in der Shell ausführen möchte, bevor man eine Datei öffnet, empfiehlt es sich, xmllint in XNEdit zu integrieren. Hierfür müssen wir dem Shell-Menü einen neuen Befehl hinzufügen.
Die Einstellungen dafür öffnet man über Preferences → Default Settings → Customize Menus → Shell Menu...
Dort wählen wir zuerst oben links New und geben bei Menu Entry einen passenden Namen für den Menüeintrag ein.
Die Einstellungen, die wir dann noch benötigen, sind:
Command Input: document
Command Output: same document
Output replaces input
Der Befehl, der ausgeführt werden soll ist:
xmllint --format -

Ein Klick noch auf OK und der neue Menüeintrag steht im Shell-Menü zur Verfügung. Danach kann nach dem Öffnen einer XML-Datei über das Shell-Menü unser XML-Formatierungsbefehl ausgeführt werden.
Kommentare
dev | Artikel: Datei ver- und entschlüsseln mit openssl - kompatibel mit dav
Andreas | Artikel: Datenanalyse in der Shell Teil 1: Basis-Tools
Einfach und cool!
Danke Andreas
Rudi | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Peter | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Damit wird Nedit durch XNedit ersetzt.
Danke!
Olaf | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Anti-Aliasing hängt von der Schriftart ab. Mit einem bitmap font sollte die Schrift klassisch wie in nedit aussehen.
Einfach unter Preferences -> Default Settings -> Text Fonts nach einer passenden Schriftart suchen.
Peter | Artikel: XNEdit - Mein NEdit-Fork mit Unicode-Support
Mettigel | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Ich hatte gedacht, dass der GX-415 im s920 deutlich mehr Dampf hat als der Raspi4.
Mein Thinclient verbraucht mit 16 GB RAM ~11 W idle, das ist das Dreifache vom RP4. Das muss man dem kleinen echt lassen... Sparsam ist er.
Olaf | Artikel: Raspberry Pi1 vs Raspberry Pi4 vs Fujitsu s920 vs Sun Ultra 45
Ergebnisse von der Ultra 80 wären natürlich interessant, insbesondere im Vergleich mit dem rpi1.