Nachdem ich neulich ein Video zum Thema AWK gefunden hatte habe ich gedacht - da geht noch mehr
Es ging dabei darum, dass man LibreOffice Calc oder ähnliche Programme nicht benötigt wenn man ein Linux-Terminal hat. Ausgehend von Garys Beispielen habe ich mir eine schnelle Liste von Anforderungen aufgestellt, die ich hier mal mit Syntaxbeispielen zu Lösung darstellen möchte.
Ich bin von einer ähnlichen Datenquelle wie Gary ausgegangen - ein einfaches Dateisystem-Listing mittels ls -l sorgte für Input. Ich musste die erste Zeile noch abschneiden damit ich sauber mit tabellarischen Daten arbeiten konnte - dafür sorgte tail -n +2.
Als erstes wird das Feld mit der Dateigröße in jeder Zeile der Ausgabe ausgegeben:
ls -l /usr/bin |tail -n +2| awk '{print $5}'
Die Anzahl der Zeilen kann man mittels wc ermitteln:
ls -l /usr/bin |tail -n +2| wc -l
Das funktioniert aber auch mit AWK:
ls -l /usr/bin |tail -n +2| awk 'END{print NR}'
Man kann die extrahierten Daten jeder Zeile durch eine vorangestellte Zeilennummer ergänzen:
ls -l /usr/bin |tail -n +2| awk '{print NR":"$5}'
Nun ein wenig Statistik: Die Berechnung des Durchschnitts (Mittelwerts) der Daten in Spalte 5 erfolgt so:
ls -l /usr/bin |tail -n +2| awk 'BEGIN{sum=0.0}{sum+=$5}END{printf("Average: %f\n",sum/NR)}'
Variablen werden von AWK immer auf 0 initialisiert - daher kann man im vorigen Statement die BEGIN Klausel auch weglassen. Es ist auch möglich, Variablen auf der Kommandozeile zu vereinbaren und dem Skript zu übergeben:
ls -l /usr/bin |tail -n +2| awk -v N=5 '{sum+=$N}END{printf("Average: %f\n",sum/NR)}'
Wir berechnen zusätzlich die Standardabweichung:
ls -l /usr/bin |tail -n +2| awk -v N=5 \
'{sum+=$N;sumsq+=$N^2}END{printf("Average: %f Std deviation: %f\n",sum/NR,sqrt((sumsq-sum^2/NR)/NR))}'
Dieses Mal wird der Median bestimmt:
ls -l /usr/bin |tail -n +2| awk -v N=5 '{print $N}'|sort -n| awk \
'{a[i++]=$1}END{x=int((i+1)/2);if (x < (i+1)/2) y=(a[x-1]+a[x])/2; else y=a[x-1]; printf("Median: %f\n",y)}'
Möchte man erfahren, ab welchem Wert ein bestimmter Prozentsatz der Eingaben jeweils unterhalb dieses Wertes liegen (Percentile), kann man das ebenfalls mittels AWK herausfinden:
ls -l /usr/bin |tail -n +2| awk -v N=5 \
'{print $N}'|sort -n| awk '{s[NR-1]=$N} END{for(i=0.1;i<=1.0;i+=0.1){printf("%d %f\n",i*100,s[int(NR*i-0.5)])}}'
Man kann mittels AWK auch Histogramme erzeugen:
ls -l /usr/bin |tail -n +2| awk -v N=5 '{print $N}'|sort -n| awk -v DELTA=150000 \
'BEGIN{delta = (DELTA == "" ? 10000 : DELTA)} \
{bucketNr = int(($0+delta) / delta);cnt[bucketNr]++;numBuckets = (numBuckets > bucketNr ? numBuckets : bucketNr)} \
END{for (bucketNr=1; bucketNr<=numBuckets; bucketNr++) {end = beg + delta;printf("%0.1f %0.1f %d\n"), beg, end, cnt[bucketNr];beg = end;}}'>hist.dat
In diesem Fall sollten wir uns auf den interessanten Teil des Histogrammes beschränken - das zeigt auch gleich, dass man mehrere Variablen auf der Kommandozeile vereinbaren kann:
ls -l /usr/bin |tail -n +2| awk -v N=5 '{print $N}'|sort -n| awk -v DELTA=1000 -v MAX=15001 \
'BEGIN{delta = (DELTA == "" ? 10000 : DELTA)} \
{if($0<15001){bucketNr = int(($0+delta) / delta);cnt[bucketNr]++;numBuckets = (numBuckets > bucketNr ? numBuckets : bucketNr)}} \
END{for (bucketNr=1; bucketNr<=numBuckets; bucketNr++) {end = beg + delta;printf "%0.1f %0.1f %d\n", beg, end, cnt[bucketNr];beg = end;}}'>hist.dat
Man kann dieses Histogramm direkt mit Gnuplot im Terminal darstellen - die Größe des Plots passt sich automatisch der Größe des Terminals an...
ls -l /usr/bin |tail -n +2| awk -v N=5 '{print $N}'|sort -n| awk -v DELTA=1000 -v MAX=15001 \
'BEGIN{delta = (DELTA == "" ? 10000 : DELTA)} \
{if($0<MAX){bucketNr = int(($0+delta) / delta);cnt[bucketNr]++;numBuckets = (numBuckets > bucketNr ? numBuckets : bucketNr)}} \
END{for (bucketNr=1; bucketNr<=numBuckets; bucketNr++) {end = beg + delta;printf "%0.1f %0.1f %d\n", beg, end, cnt[bucketNr];beg = end;}}' \
|gnuplot -p -e "set terminal dumb size $(tput cols), $(tput lines) enhanced; set autoscale;set style data histogram;set style fill solid;plot '-' using 3:xtic(1)"
Es ist möglich, nur bestimmte Zellen in der Berechnung zu benutzen - Man kann zum Beispiel anhand regulärer Ausdrücke bestimmte Zeilen ausschließen:
ls -l /usr/bin |tail -n +2| awk -v N=5 \
'{if($9 ~ /^m/){sum+=$N;sumsq+=$N^2;count++}} \
END{printf("Average: %f Std deviation: %f Count: %d\n",sum/count,sqrt((sumsq-sum^2/count)/count),count)}'
Es ist dabei auch möglich, die Groß- und Kleinschreibung zu ignorieren:
ls -l /usr/bin |tail -n +2| awk -v N=5 \
'{IGNORECASE = 1;if($9 ~ /^m/){sum+=$N;sumsq+=$N^2;count++}} \
END{printf("Average: %f Std deviation: %f Count: %d\n",sum/count,sqrt((sumsq-sum^2/count)/count),count)}'
Eine alternative Schreibweise dafür:
ls -l /usr/bin |tail -n +2| awk -v N=5 \
'IGNORECASE = 1 && $9 ~ /^m/{sum+=$N;sumsq+=$N^2;count++} \
END{printf("Average: %f Std deviation: %f Count: %d\n",sum/count,sqrt((sumsq-sum^2/count)/count),count)}'
Es ist natürlich auch möglich, die in der Berechnung zu berücksichtigenden Zeilen einfach über ihre Zeilennummern zu bestimmen:
ls -l /usr/bin |tail -n +2| awk -v N=5 \
'{if(NR >9 && NR<21){sum+=$N;sumsq+=$N^2;count++}} \
END{printf("Average: %f Std deviation: %f Count: %d\n",sum/count,sqrt((sumsq-sum^2/count)/count),count)}'
Eine alternative Schreibweise dafür:
ls -l /usr/bin |tail -n +2| awk -v N=5 \
'(NR >9 && NR<21){sum+=$N;sumsq+=$N^2;count++} \
END{printf("Average: %f Std deviation: %f Count: %d\n",sum/count,sqrt((sumsq-sum^2/count)/count),count)}'
Es ist sogar möglich, Werte über den Vergleich von Daten (Zeitpunkten) zu filtern:
ls -lt --time-style=long-iso /usr/bin|awk -v date=2020-06-09 'date<$6{print $8}'
Es gibt auch Möglichkeiten, Funktionen zu definieren - während int(n) einfach nur die Nachkommastellen abschneidet, kann man in AWK eine korrekte Rundungsfunktion wie folgt definieren:
func round(n)
{
return int(n+0.5)
}
Eine Funktion für die nächstgrößere ganze Zahl ist ebenfalls sehr einfach zu schaffen:
function ceil(n)
{
return n%1 ? int(n)+1 : n
}
Wer möchte, kann sich das hier angehängte Cheat-Sheet, das ich aus einem Template erstellt habe auch ausdrucken...
ls -l /usr/bin |tail -n +2| \
awk '{if($5>999999)print NR"\t"$1"\t"$2"\t"$3"\t"$4"\t\033[1;31m"$5"\033[0m"; \
else print NR"\t"$1"\t"$2"\t"$3"\t"$4"\t"$5;}'
Das Cheat-Sheet wurde natürlich entsprechend erweitert...
02.11.2021
Durch einen Post auf Mastodon wurde ich auf eine Idee gebracht...
29.10.2021
Ich habe bereits darüber berichtet, dass man in vielen Fällen AWK den Vorzug vor Excel und ähnlichem geben kann (und sollte!) - hier nun einige weitere Inspirationen dahingehend
26.05.2021
Ich bin neulich bei Mastodon über eine Anfrage gestolpert, wie man online schnell eine graphische Darstellung statistischer Daten mit Mittelwert usw. anfertigen könnte. Ich gab dazu einige Suchparameter ergänzt um den Schlüsselbegriff "Gnuplot" ein und fand sofort einen Artikel, der erklärte, wie man das angefragte Szenario mittels Gnuplot umsetzen könnte.
15.01.2021
Nachdem ich neulich mein AWK-Kochbuch um ein neues Rezept erweitert habe mit dem es möglich ist, einzelne Felder einer Datei regelbasiert mittels Ansi-Escape-Sequenzen unterschiedlich einzufärben, hat mich der Ansi-Steuercode-Virus wieder voll erwischt...
CI/CD mit shellcheck
13.10.2019
Ich habe mich entschlossen, in meinen diversen Shell-Projekten shellcheck als Mittel zur Qualitätssicherung einzusetzen.
Weiterlesen...Android Basteln C und C++ Chaos Datenbanken Docker dWb+ ESP Wifi Garten Geo Git(lab|hub) Go GUI Gui Hardware Java Jupyter Komponenten Links Linux Markdown Markup Music Numerik PKI-X.509-CA Python QBrowser Rants Raspi Revisited Security Software-Test sQLshell TeleGrafana Verschiedenes Video Virtualisierung Windows Upcoming...
In meinem $dayjob kam neulich die Frage auf, ob es möglich wäre, die aktuelle Softwareinstallation eines Linux-Systems als Software Bill of Materials (SBOM) zu exportieren.
Weiterlesen...Ich habe - motiviert durch meine Experimente zur Visualisierung von Paketabhängigkeiten in Linux-Installationen als interaktive Graphen - versucht, relationale Datenmodelle in ähnlicher Form zu visualisieren und dazu zwei Plugins für die sQLshell geschrieben.
Weiterlesen...Die Royal Institution hat in ihren Schätzen gegraben und die Christmas Lectures von Carl Sagan auf Youtube nochmals veröffentlicht. Meiner Ansicht nach unbedingt lohnenswert für alle, die Englisch verstehen!
Weiterlesen...Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.
Wer daran teilhaben und eventuell sogar davon profitieren möchte, muß damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.
Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...
PS: Meine öffentlichen GitHub-Repositories findet man hier - meine öffentlichen GitLab-Repositories finden sich dagegen hier.