0Pricing
Linux Command Line & Bash Scripting Mastery · Lektion

awk-Funktionen, printf-Formatierung und Berichtserstellung

Definieren Sie eigene Funktionen und verwenden Sie printf, um aus Rohdatenströmen übersichtliche Tabellenberichte zu erzeugen.

awk-Funktionen, printf-Formatierung und Berichtserstellung ist eine kostenlose Linux Command Line & Bash Scripting Mastery-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Linux Command Line & Bash Scripting Mastery-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.

Warum Funktionen und printf in awk wichtig sind

Wenn Ihre awk-Programme von Einzeilern zu mehrstufigen Pipelines wachsen, werden zwei Funktionen unverzichtbar: benutzerdefinierte Funktionen und die Formatierung mit printf.

Mit Funktionen kapseln Sie wiederverwendbare Logik – etwa einen Prozentrechner, eine Funktion zum Kürzen von Zeichenketten oder einen Einheitenumrechner –, schreiben sie einmal und rufen sie überall im selben Programm auf. Mit printf steuern Sie exakt, wie die Ausgabe aussieht: Spaltenbreiten, Nachkommastellen, Auffüllung und Ausrichtung.

Zusammen verwandeln diese Funktionen rohe Protokollzeilen in übersichtliche, gut lesbare Berichte, auf deren Grundlage Entwickler und Führungskräfte handeln können.

  • Funktionen vermeiden doppelte Logik und machen Programme isoliert testbar.
  • printf richtet Daten in Spalten fester Breite aus, sodass Berichte auch bei unterschiedlich langen Eingaben lesbar bleiben.
  • Beide Funktionen funktionieren in POSIX awk, gawk und mawk – Erweiterungen sind nicht erforderlich.

Eine benutzerdefinierte Funktion in awk definieren

Eine benutzerdefinierte Funktion wird mit dem Schlüsselwort function vor oder nach beliebigen Pattern-Action-Regeln deklariert. Die Syntax lautet:

function name(param1, param2,    local1, local2) {
    # body
    return value
}

Ein wichtiges awk-Idiom: Lokale Variablen sind einfach zusätzliche Parameter, vor denen zusätzlicher Leerraum steht. Es gibt kein Schlüsselwort local – die Konvention mit zusätzlichen Leerzeichen signalisiert, dass diese Parameter lokal sind und keine Argumente, die der Aufrufer übergibt.

  • Alle Variablen, die nicht als Parameter deklariert sind, sind standardmäßig global.
  • Funktionen können sich selbst rekursiv aufrufen.
  • return ist optional; ohne dieses Schlüsselwort gibt die Funktion eine leere Zeichenkette zurück.
#!/usr/bin/env bash
# Demonstrate a simple awk user function
echo '10 3
7 0
100 4' | awk '
function divide(a, b,    result) {
    if (b == 0) return "ERR"
    result = a / b
    return result
}
{
    print $1 "/" $2 " = " divide($1, $2)
}
'

Funktionen mit Zeichenkettenlogik

Funktionen sind besonders nützlich für wiederkehrende Operationen mit Zeichenketten. Denken Sie etwa an das Entfernen von Leerzeichen am Anfang und Ende – eine Verarbeitung, die rohe Protokolldaten vor Vergleichen oder der Ausgabe häufig benötigen.

Das folgende Beispiel definiert trim(s) mithilfe von gsub und verwendet die Funktion für jeden Datensatz, sodass die Hauptregel übersichtlich und gut lesbar bleibt.

  • gsub(regex, replacement, target) verändert target direkt und gibt die Anzahl der Ersetzungen zurück.
  • Wenn Sie die Logik für reguläre Ausdrücke in eine Funktion auslagern, bleibt der Regelblock auf die Fachlogik konzentriert.
  • Sie können die Funktion testen, indem Sie in einem BEGIN-Block direkt von Hand erstellte Zeichenketten übergeben.
#!/usr/bin/env bash
# trim() strips leading/trailing spaces; used to normalise CSV-like data
printf '  alice , 90 \n bob , 85 \n  carol , 92 \n' | awk -F',' '
function trim(s) {
    gsub(/^[ \t]+|[ \t]+$/, "", s)
    return s
}
{
    name  = trim($1)
    score = trim($2)
    print name, score
}
'

Einführung in printf in awk

printf in awk folgt denselben Konventionen wie in C und beim integrierten printf von Bash. Der entscheidende Unterschied zu print besteht darin, dass printf niemals automatisch einen Zeilenumbruch anhängt – Sie müssen \n selbst hinzufügen.

Häufige Formatbezeichner:

  • %s – Zeichenkette
  • %d – Ganzzahl
  • %f – Gleitkommazahl
  • %e – wissenschaftliche Schreibweise
  • %g – die kürzere Darstellung von %f/%e

Breite und Genauigkeit steuern Sie, indem Sie Zahlen zwischen % und dem Bezeichner platzieren: %-20s richtet eine Zeichenkette in einem 20 Zeichen breiten Feld linksbündig aus; %8.2f erzeugt eine Gleitkommazahl mit einer Breite von 8 und 2 Nachkommastellen.

#!/usr/bin/env bash
# printf format specifiers in awk
echo '' | awk '
BEGIN {
    printf "%s\n",        "plain string"
    printf "%10s\n",     "right-pad"
    printf "%-10s|\n",   "left-pad"
    printf "%8.2f\n",    3.14159
    printf "%08d\n",     42
    printf "%e\n",       123456.789
}
'

Mit printf eine Berichtskopfzeile erstellen

Ein professionell gestalteter Bericht benötigt eine Kopfzeile und eine Trennlinie. Der BEGIN-Block ist der natürliche Ort dafür, da er einmal vor der Verarbeitung der Eingaben ausgeführt wird.

Der entscheidende Punkt ist, die Breiten exakt abzugleichen: Die Kopfzeile muss dieselben Breiten verwenden wie die Datenzeilen. Wenn Sie Breitenkonstanten in BEGIN (oder in einer Funktion) definieren, bleibt alles synchron, wenn Sie die Spaltenbreiten später anpassen.

  • Verwenden Sie printf mit einer Trennzeichenkette aus Bindestrichen, um die Trennlinie zu zeichnen.
  • Beenden Sie Kopfzeilen immer mit \n.
  • Kombinieren Sie eine BEGIN-Kopfzeile, Zeilen pro Datensatz und einen END-Fußbereich zu einer vollständigen Berichtsstruktur.
#!/usr/bin/env bash
# Print a report header in BEGIN, data rows per-record, total in END
printf 'alice 9200 12\nbob 8750 10\ncarol 10400 14\n' | awk '
BEGIN {
    printf "%-10s %10s %6s %12s\n", "Name", "Salary", "Months", "Annual"
    printf "%s\n", "----------------------------------------------"
    total = 0
}
{
    annual = $2 * $3
    total += annual
    printf "%-10s %10d %6d %12d\n", $1, $2, $3, annual
}
END {
    printf "%s\n", "----------------------------------------------"
    printf "%-10s %10s %6s %12d\n", "TOTAL", "", "", total
}
'

Benutzerdefinierte Funktionen für Formatierungslogik

Beim Erstellen mehrspaltiger Berichte benötigen Sie häufig an mehreren Stellen denselben Formatierungsaufruf – etwa zum Darstellen eines Prozentbalkens oder zum Umrechnen von Bytes in eine menschenlesbare Einheit. Wenn Sie dies in eine Funktion auslagern, vermeiden Sie doppelte Logik und können das Format einfach global ändern.

Die folgende Funktion wandelt Bytes in KB, MB oder GB um und gibt eine formatierte Zeichenkette zurück. Die aufrufende Regel übergibt einfach $NF (das letzte Feld) und gibt den zurückgegebenen Wert aus.

#!/usr/bin/env bash
# human_bytes() converts raw byte counts to KB/MB/GB strings
printf 'var.log 1024\naccess.log 2097152\ncore.dump 1073741824\ntiny.txt 512\n' | awk '
function human_bytes(n,    s) {
    if (n >= 1073741824) { s = sprintf("%.1f GB", n/1073741824) }
    else if (n >= 1048576) { s = sprintf("%.1f MB", n/1048576) }
    else if (n >= 1024)    { s = sprintf("%.1f KB", n/1024) }
    else                   { s = sprintf("%d B",    n) }
    return s
}
BEGIN { printf "%-20s %10s\n", "File", "Size"; print "------------------------------" }
{ printf "%-20s %10s\n", $1, human_bytes($2) }
'

Daten vor der Ausgabe in Arrays sammeln

Für echte Berichte werden häufig Summen, Durchschnittswerte oder Rangfolgen benötigt – Werte, die Sie erst berechnen können, wenn Sie alle Eingaben gesehen haben. Das typische Vorgehen ist:

  • Daten während der Verarbeitung der einzelnen Datensätze in assoziativen Arrays sammeln.
  • Abgeleitete Werte (Durchschnittswerte, Prozentsätze) in END berechnen.
  • Formatierte Ausgaben nur aus END erzeugen, damit sich die Spaltenbreiten an den vollständigen Datensatz anpassen können.

Dieses Muster der verzögerten Ausgabe gehört zu den leistungsfähigsten Redewendungen bei der Berichtserstellung mit awk. Das folgende Beispiel zählt die Anfragen und Antwort-Bytes je HTTP-Statuscode aus einem Access-Log.

#!/usr/bin/env bash
# Summarise an nginx-style access log by HTTP status code
printf '127.0.0.1 200 1234\n127.0.0.1 404 512\n10.0.0.2 200 8900\n10.0.0.3 500 256\n10.0.0.4 200 4096\n10.0.0.5 404 300\n' | awk '
{
    status  = $2
    bytes   = $3
    count[status]++
    total_bytes[status] += bytes
}
END {
    printf "%-8s %8s %14s\n", "Status", "Requests", "Total Bytes"
    print  "-----------------------------------"
    for (s in count)
        printf "%-8s %8d %14d\n", s, count[s], total_bytes[s]
}
'

Rekursive Funktionen in awk

awk unterstützt Rekursion. Ein klassischer Anwendungsfall ist die Berechnung von Fakultäten oder die Erzeugung sich wiederholender Zeichenketten (beispielsweise einer Linie aus Bindestrichen in der Breite des Terminals). Rekursion wird in awk seltener verwendet als in universell einsetzbaren Programmiersprachen, funktioniert aber korrekt und ist in allen gängigen Implementierungen verfügbar.

Das folgende Beispiel definiert eine rekursive Funktion repeat(s, n) und verwendet sie, um Trennlinien zu zeichnen, die automatisch der Breite der längsten Datenzeile entsprechen – fest codierte Bindestriche sind nicht erforderlich.

  • Vermeiden Sie bei großen Eingaben tiefe Rekursion – awk verfügt über keine Tail-Call-Optimierung.
  • Für einfache Wiederholungen ist sprintf("%*s", n, "") zusammen mit gsub(/ /, "-") schneller, aber weniger anschaulich.
#!/usr/bin/env bash
# Recursive repeat() to build separator lines dynamically
awk '
function repeat(s, n,    acc) {
    if (n <= 0) return ""
    acc = s repeat(s, n-1)
    return acc
}
BEGIN {
    header = sprintf("%-15s %10s %10s", "Metric", "Current", "Target")
    sep    = repeat("-", length(header))
    print sep
    print header
    print sep
    printf "%-15s %10.1f %10.1f\n", "CPU %",     72.4, 60.0
    printf "%-15s %10.1f %10.1f\n", "Mem GB",    14.2, 16.0
    printf "%-15s %10d %10d\n",   "Open FDs", 1024,  800
    print sep
}
' /dev/null

Mit printf in awk in eine Datei oder Pipeline schreiben

Das printf von awk (ebenso wie print) kann die Ausgabe in Dateien umleiten oder an Shell-Befehle weiterleiten – direkt innerhalb des awk-Programms, ohne das gesamte Programm in einer Subshell zu verpacken.

  • printf "..." > "file.txt" – schreibt in eine Datei (kürzt sie einmal und hängt danach während desselben Laufs weitere Ausgaben an).
  • printf "..." >> "file.txt" – hängt Ausgaben an eine Datei an.
  • printf "..." | "sort -rn" – leitet die Ausgabe an einen Shell-Befehl weiter; awk hält die Pipeline über mehrere Datensätze hinweg offen und schließt sie am Ende des Programms.

Ein häufiges Muster besteht darin, einen einzigen Durchlauf durch ein Log in mehrere Ausgabedateien pro Status oder Host aufzuteilen und so wiederholte Scans einer großen Datei zu vermeiden.

#!/usr/bin/env bash
# Route records into per-status files using print redirection
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

printf '200 /index.html\n404 /missing\n200 /api/data\n500 /crash\n404 /lost\n' | awk -v out="$tmpdir" '
{
    file = out "/" $1 ".log"
    printf "%-6s %s\n", $1, $2 > file
}
END {
    close(file)  # flush all open handles
}
'

echo "=== 200 ==="
cat "$tmpdir/200.log"
echo "=== 404 ==="
cat "$tmpdir/404.log"

Einen CSV-Bericht mit awk erzeugen

Nicht alle Berichte sind für Menschen bestimmt. Manchmal muss die Ausgabe als maschinenlesbares CSV vorliegen, das von einer Tabellenkalkulation oder einer nachgelagerten Pipeline verarbeitet wird. Das printf von awk eignet sich dafür gut: Setzen Sie OFS auf ein Komma oder steuern Sie jedes Trennzeichen explizit.

Für robustes CSV aus awk gelten zwei wichtige Regeln:

  • Umschließen Sie Felder, die Kommas oder Zeilenumbrüche enthalten können, mit doppelten Anführungszeichen.
  • Maskieren Sie wörtliche doppelte Anführungszeichen innerhalb eines Feldes, indem Sie sie verdoppeln: He said ""hello"".

Die folgende Funktion csv_field(s) kapselt diese Maskierungslogik, sodass sie konsistent auf jedes Zeichenkettenfeld angewendet werden kann.

#!/usr/bin/env bash
# Emit a valid CSV report from space-separated input
printf 'alice engineer 95000\nbob "sales,mgr" 82000\ncarol developer 110000\n' | awk '
function csv_field(s,    safe) {
    safe = s
    gsub(/"/, "\"\"" , safe)   # double any embedded quotes
    return "\"" safe "\""       # wrap in quotes
}
BEGIN { print "Name,Role,Salary" }
{
    printf "%s,%s,%d\n", csv_field($1), csv_field($2), $3
}
'

Von Anfang bis Ende: Ein vollständiger Access-Log-Bericht

Dieses abschließende Beispiel führt alles zusammen: benutzerdefinierte Funktionen, printf-Formatierung, das Sammeln von Daten in Arrays sowie einen strukturierten Kopf- und Fußbereich. Die Eingabe ist ein vereinfachtes Web-Access-Log; die Ausgabe ist eine lesbare Übersichtstabelle mit Summen pro Methode und einer Gesamtsumme.

Wichtige verwendete Techniken:

  • count[method]++ und bytes[method] += size sammeln Statistiken pro Methode in einem einzigen Durchlauf.
  • human_bytes() (aus einer früheren Szene) konvertiert Byte-Summen.
  • printf mit übereinstimmenden Breiten in Kopfzeile, Daten und Fußzeile sorgt dafür, dass die Tabelle unabhängig vom Umfang der Eingabe ausgerichtet bleibt.
  • Der END-Block durchläuft das Array mit for (k in arr) und erzeugt die sortierte Ausgabe über eine Pipeline zu sort.
#!/usr/bin/env bash
# Full access log report: method breakdown with human-readable bytes
printf 'GET /index 200 4096\nPOST /api 201 512\nGET /img 200 102400\nDELETE /item 204 0\nPOST /login 401 256\nGET /style 200 8192\n' | awk '
function human_bytes(n,    s) {
    if (n >= 1048576) s = sprintf("%.1f MB", n/1048576)
    else if (n >= 1024) s = sprintf("%.1f KB", n/1024)
    else s = sprintf("%d B", n)
    return s
}
{
    method = $1
    size   = $4
    count[method]++
    bytes[method] += size
    grand_count++
    grand_bytes += size
}
END {
    fmt = "%-10s %8s %15s\n"
    sep = "----------------------------------"
    printf fmt, "Method", "Requests", "Bytes"
    print sep
    for (m in count)
        printf "%-10s %8d %15s\n", m, count[m], human_bytes(bytes[m])
    print sep
    printf "%-10s %8d %15s\n", "TOTAL", grand_count, human_bytes(grand_bytes)
}
'

Wissenscheck: Lokale Variablen in awk-Funktionen

Welche der folgenden Varianten deklariert result gemäß der POSIX-Konvention korrekt als lokale Variable innerhalb einer awk-Funktion?

Lektionsrückblick: awk-Funktionen, printf und Berichtserstellung

In dieser Lektion haben Sie gelernt, wie Sie awk-Programme in Produktionsqualität schreiben, die aus Rohdatenströmen formatierte Berichte erzeugen. Das sollten Sie mitnehmen:

  • Benutzerfunktionen werden mit function name(params, locals) deklariert. Zusätzliche Leerzeichen vor den Parametern für lokale Variablen entsprechen der POSIX-Konvention – ein Schlüsselwort local gibt es nicht.
  • printf ermöglicht eine präzise Steuerung der Ausgabe: Breite (%10s), Ausrichtung (%-10s) und Genauigkeit (%8.2f). Denken Sie daran, \n explizit hinzuzufügen.
  • Verwenden Sie BEGIN, um Kopfzeilen und Trennlinien auszugeben, Regeln pro Datensatz, um Daten zu sammeln, und END, um Summen zu berechnen und den fertigen Bericht auszugeben.
  • Leiten Sie die Ausgabe von printf innerhalb von awk in Dateien (> file) oder Pipelines (| "sort") um, um Berichte aufzuteilen oder die Ausgabe nachträglich zu verarbeiten.
  • Umschließen Sie Zeichenkettenfelder bei der CSV-Ausgabe mit einer Hilfsfunktion csv_field(), damit eingebettete Kommas und Anführungszeichen sicher behandelt werden.
  • Funktionen zum Umrechnen von Einheiten (human_bytes), Wiederholen von Zeichen (repeat) oder Bereinigen von Zeichenketten (trim, csv_field) sollten Sie in einer persönlichen awk-Bibliothek aufbewahren – sie lassen sich projektübergreifend problemlos kombinieren.

Häufig gestellte Fragen

Ist die Lektion „awk-Funktionen, printf-Formatierung und Berichtserstellung“ kostenlos?

Ja — der vollständige Text von „awk-Funktionen, printf-Formatierung und Berichtserstellung“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Linux Command Line & Bash Scripting Mastery-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „awk-Funktionen, printf-Formatierung und Berichtserstellung“?

Definieren Sie eigene Funktionen und verwenden Sie printf, um aus Rohdatenströmen übersichtliche Tabellenberichte zu erzeugen. Du übst Linux Command Line & Bash Scripting Mastery mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Linux Command Line & Bash Scripting Mastery zu starten?

Keine Vorkenntnisse erforderlich. Linux Command Line & Bash Scripting Mastery auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „awk-Funktionen, printf-Formatierung und Berichtserstellung“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Linux Command Line & Bash Scripting Mastery-Lektion Code schreiben und ausführen?

Ja. Jede Linux Command Line & Bash Scripting Mastery-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Datensätze, Felder und benutzerdefinierte Trennzeichen in awk
  2. Muster, Bereiche und BEGIN-/END-Blöcke
  3. Aggregation mit awk-Arrays und Gruppierung
  4. awk-Funktionen, printf-Formatierung und Berichtserstellung
← Zurück zu Linux Command Line & Bash Scripting Mastery