0Pricing
DevOps Bootcamp · Lezione

Funzioni awk, formattazione con printf e generazione di report

Definisca funzioni personalizzate e usi printf per generare report tabellari curati a partire da flussi di dati grezzi.

Funzioni awk, formattazione con printf e generazione di report è una lezione DevOps Bootcamp gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento DevOps Bootcamp, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso DevOps Bootcamp include 4 lezioni in totale.

Perché le funzioni e printf sono importanti in awk

Quando i programmi awk passano da una riga di comando a pipeline con più passaggi, due funzionalità diventano essenziali: le funzioni definite dall'utente e la formattazione con printf.

Le funzioni consentono di incapsulare logica riutilizzabile, come un calcolatore di percentuali, un eliminatore di spazi o un convertitore di unità, così da scriverla una sola volta e richiamarla ovunque nello stesso programma. printf consente di controllare esattamente l'aspetto dell'output: larghezza delle colonne, posizioni decimali, riempimento e allineamento.

Insieme trasformano righe di log grezze in report curati e leggibili, su cui tecnici e responsabili possono basare le proprie decisioni.

  • Le funzioni riducono la duplicazione e rendono i programmi testabili in isolamento.
  • printf allinea i dati in colonne di larghezza fissa, così i report restano leggibili anche con lunghezze dell'input variabili.
  • Entrambe le funzionalità sono disponibili in POSIX awk, gawk e mawk, senza bisogno di estensioni.

Definizione di una funzione utente in awk

Una funzione utente si dichiara con la parola chiave function, prima o dopo qualsiasi regola pattern-azione. La sintassi è:

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

Un idioma di awk importante: le variabili locali sono semplicemente parametri aggiuntivi preceduti da spazi aggiuntivi. Non esiste una parola chiave local: la convenzione degli spazi aggiuntivi segnala che quei parametri sono locali e non argomenti passati dal chiamante.

  • Tutte le variabili non dichiarate come parametri sono globali per impostazione predefinita.
  • Le funzioni possono richiamare se stesse in modo ricorsivo.
  • return è facoltativo; in sua assenza la funzione restituisce una stringa vuota.
#!/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)
}
'

Funzioni con logica sulle stringhe

Le funzioni sono particolarmente utili per ripetere operazioni sulle stringhe. Si consideri la rimozione degli spazi iniziali e finali, un'operazione spesso necessaria sui dati grezzi dei log prima del confronto o della generazione di report.

L'esempio seguente definisce trim(s) usando gsub e la utilizza per ogni record, mantenendo la regola principale pulita e leggibile.

  • gsub(regex, replacement, target) modifica target direttamente e restituisce il numero di sostituzioni.
  • Inserire la logica dell'espressione regolare in una funzione fa sì che il blocco della regola resti focalizzato sulla logica di business.
  • È possibile eseguire unit test passando stringhe create manualmente direttamente in un blocco BEGIN.
#!/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
}
'

Introduzione a printf in awk

In awk, printf segue le stesse convenzioni del C e del comando integrato printf di Bash. La differenza principale rispetto a print è che printf non aggiunge mai automaticamente un a capo: deve aggiungere personalmente \n.

Specificatori di formato comuni:

  • %s — stringa
  • %d — intero
  • %f — virgola mobile
  • %e — notazione scientifica
  • %g — il più breve tra %f/%e

L'ampiezza e la precisione si controllano inserendo dei numeri tra % e lo specificatore: %-20s allinea a sinistra in un campo di 20 caratteri; %8.2f assegna a un numero in virgola mobile un campo di 8 caratteri con 2 cifre decimali.

#!/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
}
'

Creazione dell'intestazione di un report con printf

Un report curato ha bisogno di una riga di intestazione e di una riga separatrice. Il blocco BEGIN è il posto naturale in cui produrle: viene eseguito una volta prima dell'elaborazione dell'input.

Il trucco consiste nel far corrispondere le larghezze dell'intestazione esattamente alle larghezze usate nelle righe dei dati. Definire costanti per le larghezze in BEGIN (o in una funzione) mantiene tutto sincronizzato quando in seguito si modificano le larghezze delle colonne.

  • Usi printf con una stringa di trattini come separatore per tracciare la riga divisoria.
  • Termini sempre le righe dell'intestazione con \n.
  • Combini un'intestazione in BEGIN, le righe per record e un piè di pagina in END per ottenere una struttura completa del report.
#!/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
}
'

Funzioni utente per la logica di formattazione

Quando si creano report con più colonne, è comune dover usare la stessa chiamata di formattazione in diversi punti, ad esempio per visualizzare una barra percentuale o convertire i byte in un'unità leggibile. Inserirla in una funzione evita la duplicazione e rende semplice modificare il formato globalmente.

La funzione seguente converte i byte in KB, MB o GB e restituisce una stringa formattata. La regola chiamante passa semplicemente $NF (l'ultimo campo) e stampa il risultato.

#!/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) }
'

Accumulo dei dati negli array prima della stampa

I report reali richiedono spesso totali, medie o classifiche: valori che non è possibile calcolare finché non si è esaminato tutto l'input. Il modello è il seguente:

  • Accumuli i dati in array associativi durante la fase di elaborazione dei record.
  • Calcoli i valori derivati (medie, percentuali) in END.
  • Produca l'output formattato solo da END, così le larghezze possono adattarsi all'intero dataset.

Questo modello di output differito è uno degli idiomi più potenti per generare report con awk. L'esempio seguente conta le richieste e i byte di risposta per codice di stato HTTP a partire da un 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]
}
'

Funzioni ricorsive in awk

awk supporta la ricorsione. Un caso d'uso classico consiste nel calcolare fattoriali o generare stringhe ripetitive (come una riga di trattini della larghezza del terminale). La ricorsione è meno comune in awk rispetto ai linguaggi general purpose, ma funziona correttamente ed è disponibile in tutte le implementazioni principali.

L'esempio seguente definisce la funzione ricorsiva repeat(s, n) e la utilizza per tracciare righe separatrici che corrispondono automaticamente alla larghezza della riga di dati più ampia, senza bisogno di trattini codificati a priori.

  • Eviti la ricorsione profonda su input di grandi dimensioni: awk non dispone dell'ottimizzazione delle chiamate terminali.
  • Per una semplice ripetizione, sprintf("%*s", n, "") con gsub(/ /, "-") è più veloce, ma meno esemplificativo.
#!/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

printf su un file o una pipeline all'interno di awk

Il comando printf di awk (così come print) può reindirizzare l'output verso file o inviarlo tramite pipe a comandi shell, direttamente dal programma awk, senza racchiudere tutto in una subshell.

  • printf "..." > "file.txt" — scrive in un file (lo tronca una volta, poi aggiunge i dati durante la stessa esecuzione).
  • printf "..." >> "file.txt" — aggiunge dati a un file.
  • printf "..." | "sort -rn" — invia l'output a un comando shell; awk mantiene aperta la pipe tra i record e la chiude al termine del programma.

Un modello comune consiste nel suddividere una singola scansione di un log in più file di output, uno per stato o per host, evitando scansioni ripetute di un file di grandi dimensioni.

#!/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"

Generazione di un report CSV con awk

Non tutti i report sono destinati alle persone. A volte l'output deve essere un CSV leggibile dalle macchine, da fornire a un foglio di calcolo o a una pipeline successiva. Il comando printf di awk gestisce questo caso in modo semplice: imposti OFS su una virgola oppure controlli esplicitamente ogni delimitatore.

Due regole importanti per ottenere CSV affidabili con awk:

  • Faccia l'escape delle virgolette doppie letterali all'interno di un campo raddoppiandole: He said ""hello"".

La funzione csv_field(s) seguente incapsula questa logica di quoting, così può essere applicata in modo coerente a ogni campo stringa.

#!/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
}
'

Da capo a capo: un report completo di un access log

Questo esempio finale riunisce tutti gli elementi: funzioni definite dall'utente, formattazione con printf, accumulo negli array e un'intestazione e un piè di pagina strutturati. L'input è un access log web semplificato; l'output è una tabella di riepilogo leggibile dalle persone, con i totali per metodo e una riga del totale complessivo.

Tecniche principali utilizzate:

  • count[method]++ e bytes[method] += size accumulano le statistiche per metodo in un'unica scansione.
  • human_bytes() (da una scena precedente) converte i totali dei byte.
  • printf con larghezze corrispondenti nell'intestazione, nei dati e nel piè di pagina mantiene allineata la tabella indipendentemente dalle dimensioni dell'input.
  • Il blocco END scorre l'array con for (k in arr) e produce l'output ordinato tramite una pipe verso 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)
}
'

Verifica delle conoscenze: variabili locali nelle funzioni awk

Quale delle seguenti dichiarazioni definisce correttamente result come variabile locale all'interno di una funzione awk, secondo la convenzione POSIX?

Riepilogo della lezione: funzioni awk, printf e generazione di report

In questa lezione ha imparato a scrivere programmi awk di qualità adatta alla produzione, in grado di generare report formattati da flussi di dati grezzi. Ecco cosa ricordare:

  • Le funzioni definite dall'utente vengono dichiarate con function name(params, locals). Gli spazi aggiuntivi prima dei parametri delle variabili locali sono la convenzione POSIX: non esiste alcuna parola chiave local.
  • printf offre un controllo preciso sull'output: larghezza (%10s), allineamento (%-10s) e precisione (%8.2f). Ricordi di aggiungere esplicitamente \n.
  • Utilizzi BEGIN per produrre intestazioni e separatori, le regole per record per accumulare i dati e END per calcolare i totali e stampare il report completato.
  • Reindirizzi l'output di printf verso file (> file) o pipeline (| "sort") dall'interno di awk per suddividere i report o post-elaborare l'output.
  • Racchiuda i campi stringa in un helper csv_field() quando produce CSV, per gestire in modo sicuro virgole e virgolette incorporate.
  • Vale la pena conservare in una libreria awk personale le funzioni che convertono unità (human_bytes), ripetono caratteri (repeat) o ripuliscono stringhe (trim, csv_field): si combinano facilmente tra diversi progetti.

Domande Frequenti

La lezione «Funzioni awk, formattazione con printf e generazione di report» è gratuita?

Sì — il testo completo di «Funzioni awk, formattazione con printf e generazione di report» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso DevOps Bootcamp, passa a CoddyKit PRO. Il corso DevOps Bootcamp include 4 lezioni in totale.

Cosa imparerò in «Funzioni awk, formattazione con printf e generazione di report»?

Definisca funzioni personalizzate e usi printf per generare report tabellari curati a partire da flussi di dati grezzi. Eserciti DevOps Bootcamp con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare DevOps Bootcamp?

Non è richiesta alcuna esperienza precedente. DevOps Bootcamp su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Funzioni awk, formattazione con printf e generazione di report»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione DevOps Bootcamp?

Sì. Ogni lezione DevOps Bootcamp include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Record, campi e separatori personalizzati in awk
  2. Pattern, intervalli e blocchi BEGIN/END
  3. Aggregazione con array e raggruppamenti in awk
  4. Funzioni awk, formattazione con printf e generazione di report
← Torna a DevOps Bootcamp