awk-funktioner, printf-formatering och rapportgenerering
Definiera egna funktioner och använd printf för att skapa välformaterade tabellrapporter från rådataströmmar.
awk-funktioner, printf-formatering och rapportgenerering är en gratis lektion i Bemästra Linux-kommandoraden och Bash-skriptning på CoddyKit. Detta är lektion 4 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Bemästra Linux-kommandoraden och Bash-skriptning, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Bemästra Linux-kommandoraden och Bash-skriptning innehåller totalt 4 lektioner.
Varför funktioner och printf är viktiga i awk
När dina awk-program växer från enradsuttryck till pipeliner med flera steg blir två funktioner nödvändiga: användardefinierade funktioner och printf-formatering.
Funktioner låter dig kapsla in återanvändbar logik — en procentberäknare, en funktion som tar bort överflödiga blanksteg eller en enhetsomvandlare — så att du skriver den en gång och kan anropa den var som helst i samma program. Med printf kan du styra exakt hur utdata ser ut: kolumnbredder, decimaler, utfyllnad och justering.
Tillsammans omvandlar de råa loggrader till välformaterade, lättlästa rapporter som ingenjörer och chefer kan agera utifrån.
- Funktioner minskar duplicering och gör program möjliga att testa isolerat.
printfjusterar data i kolumner med fast bredd, så att rapporter förblir lättlästa även när indatans längder varierar.- Båda funktionerna fungerar i POSIX awk, gawk och mawk — inga tillägg behövs.
Definiera en användarfunktion i awk
En användarfunktion deklareras med nyckelordet function, före eller efter valfria mönster-åtgärdsregler. Syntaxen är:
function name(param1, param2, local1, local2) {
# body
return value
}Ett viktigt awk-idiom: lokala variabler är helt enkelt extra parametrar med extra blanksteg framför sig. Det finns inget nyckelord local — konventionen med extra blanksteg visar att parametrarna är lokala och inte argument som anroparen skickar in.
- Alla variabler som inte deklareras som parametrar är globala som standard.
- Funktioner kan anropa sig själva rekursivt.
returnär valfritt; utan det returnerar funktionen en tom sträng.
#!/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)
}
'Funktioner med stränglogik
Funktioner är särskilt användbara för återkommande strängoperationer. Tänk på att ta bort inledande och avslutande blanksteg — något som rå loggdata ofta behöver innan jämförelser eller rapportering.
Exemplet nedan definierar trim(s) med hjälp av gsub och använder den för varje post, så att huvudregeln förblir ren och lättläst.
gsub(regex, replacement, target)ändrar target på plats och returnerar antalet ersättningar.- Om du placerar reguljära uttryckets logik i en funktion kan regelblocket fokusera på affärslogiken.
- Du kan enhetstesta genom att skicka egenskapade strängar direkt i ett
BEGIN-block.
#!/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
}
'Introduktion till printf i awk
printf i awk följer samma konventioner som C och Bashs inbyggda printf. Den viktigaste skillnaden mot print är att printf aldrig lägger till en radbrytning automatiskt — du måste själv lägga till \n.
Vanliga formatangivelser:
%s— sträng%d— heltal%f— flyttal%e— vetenskaplig notation%g— den kortare av%f/%e
Bredd och precision styrs genom att placera siffror mellan % och formatangivelsen: %-20s vänsterjusterar i ett fält med 20 tecken; %8.2f ger ett flyttal i ett 8 tecken brett fält med 2 decimaler.
#!/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
}
'Skapa en rapporthuvudrad med printf
En välformaterad rapport behöver en rubrikrad och en avskiljarrad. Blocket BEGIN är den naturliga platsen att skriva ut dessa på — det körs en gång innan någon indata bearbetas.
Tricket är att matcha bredderna i rubriken exakt med bredderna som används i dataraderna. Genom att definiera breddkonstanter i BEGIN (eller i en funktion) hålls allt synkroniserat när du senare justerar kolumnbredderna.
- Använd
printfmed en avskiljarsträng av bindestreck för att rita skiljelinjen. - Avsluta alltid rubrikrader med
\n. - Kombinera en
BEGIN-rubrik, rader per post och enEND-sidfot för en komplett rapportstruktur.
#!/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
}
'Användarfunktioner för formateringslogik
När du bygger rapporter med flera kolumner behöver du ofta samma formateringsanrop på flera ställen — till exempel för att visa en procentstapel eller omvandla byte till en lättläst enhet. Genom att placera detta i en funktion undviker du duplicering och gör formatet enkelt att ändra globalt.
Funktionen nedan omvandlar byte till KB, MB eller GB och returnerar en formaterad sträng. Den anropande regeln skickar helt enkelt in $NF (det sista fältet) och skriver ut det som returneras.
#!/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) }
'Samla data i matriser innan utskrift
Verkliga rapporter behöver ofta totalsummor, medelvärden eller rangordningar – värden som inte kan beräknas förrän alla indata har lästs in. Mönstret är:
- Samla data i associativa matriser under fasen där varje post behandlas.
- Beräkna härledda värden (medelvärden, procenttal) i
END. - Skriv endast ut formaterade resultat från
END, så att kolumnbredderna kan anpassas efter hela datamängden.
Detta mönster med fördröjd utskrift är ett av de mest kraftfulla idiomen när man genererar rapporter i awk. Exemplet nedan räknar antalet förfrågningar och antalet svarbyte per HTTP-statuskod från en åtkomstlogg.
#!/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]
}
'Rekursiva funktioner i awk
awk stöder rekursion. Ett klassiskt användningsområde är att beräkna fakulteter eller generera upprepade strängar (till exempel en rad med bindestreck som är lika bred som terminalen). Rekursion är mindre vanligt i awk än i programspråk för allmänna ändamål, men fungerar korrekt och finns i alla större implementationer.
Exemplet nedan definierar en rekursiv funktion repeat(s, n) och använder den för att rita avgränsningslinjer som automatiskt matchar bredden på den bredaste dataraden – inga hårdkodade bindestreck behövs.
- Undvik djup rekursion för stora indata – awk har ingen optimering av svansanrop.
- För enkel upprepning är
sprintf("%*s", n, "")tillsammans medgsub(/ /, "-")snabbare, men mindre pedagogiskt.
#!/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/nullprintf till en fil eller pipeline i awk
aw:s printf (och print) kan omdirigera utdata till filer eller skicka den till skalkommandon via en pipe – direkt inifrån awk-programmet, utan att hela programmet behöver köras i ett subshell.
printf "..." > "file.txt"– skriver till en fil (tömmer filen en gång och lägger sedan till data under samma körning).printf "..." >> "file.txt"– lägger till data i en fil.printf "..." | "sort -rn"– skickar data till ett skalkommando via en pipe; awk håller pipen öppen mellan posterna och stänger den när programmet avslutas.
Ett vanligt mönster är att dela upp en enda genomgång av en logg i flera utdatafiler, en per status eller värd, så att man slipper läsa igenom en stor fil flera gånger.
#!/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"Generera en CSV-rapport med awk
Alla rapporter är inte avsedda för människor. Ibland måste utdata vara maskinläsbar CSV som kan matas in i ett kalkylark eller en efterföljande pipeline. aw:s printf hanterar detta smidigt: ange OFS till ett kommatecken eller styr varje avgränsare uttryckligen.
Två viktiga regler för robust CSV från awk:
- Omslut fält som kan innehålla kommatecken eller radbrytningar med dubbla citattecken.
- Escape:a alla bokstavliga dubbla citattecken i ett fält genom att dubblera dem:
He said ""hello"".
Funktionen csv_field(s) nedan kapslar in denna citeringslogik, så att den kan användas konsekvent för varje strängfält.
#!/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
}
'Från början till slut: en komplett åtkomstloggsrapport
Det här slutliga exemplet knyter ihop allt: användardefinierade funktioner, formatering med printf, insamling i matriser samt en strukturerad sidhuvud- och sidfotsdel. Indata är en förenklad åtkomstlogg från webben; utdata är en lättläst sammanfattningstabell med totalsummor per metod och en rad med totalsumman.
Viktiga tekniker:
count[method]++ochbytes[method] += sizesamlar statistik per metod i en enda genomgång.human_bytes()(från en tidigare scen) omvandlar byte-totaler.printfmed matchande bredder i sidhuvud, data och sidfot ser till att tabellen förblir justerad oavsett indatans storlek.- Blocket
ENDitererar över matrisen medfor (k in arr)och skriver ut sorterade resultat via en pipe tillsort.
#!/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)
}
'Kunskapskontroll: lokala variabler i awk-funktioner
Vilket av följande deklarerar korrekt result som en lokal variabel i en awk-funktion enligt POSIX-konventionen?
Lektionssammanfattning: awk-funktioner, printf och rapportgenerering
I den här lektionen har Ni lärt Er att skriva awk-program med produktionskvalitet som genererar formaterade rapporter från rådataströmmar. Detta bör Ni ta med Er:
- Användardefinierade funktioner deklareras med
function name(params, locals). Extra blanksteg före parametrarna för lokala variabler är POSIX-konventionen – det finns inget nyckelordlocal. - printf ger exakt kontroll över utdata: bredd (
%10s), justering (%-10s) och precision (%8.2f). Kom ihåg att lägga till\nuttryckligen. - Använd BEGIN för att skriva ut sidhuvuden och avgränsare, regler per post för att samla data och END för att beräkna totalsummor och skriva ut den färdiga rapporten.
- Omdirigera utdata från
printftill filer (> file) eller pipelines (| "sort") inifrån awk för att dela upp rapporter eller efterbehandla utdata. - Omslut strängfält med en hjälpfunktion csv_field() när Ni skriver CSV, så att inbäddade kommatecken och citattecken hanteras säkert.
- Funktioner som omvandlar enheter (
human_bytes), upprepar tecken (repeat) eller rensar strängar (trim,csv_field) är värda att spara i ett personligt awk-bibliotek – de kan enkelt kombineras mellan projekt.
Lär dig Bash med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 22
- Lektioner
- 88
Vanliga frågor
Är lektionen ”awk-funktioner, printf-formatering och rapportgenerering” gratis?
Ja – hela texten till ”awk-funktioner, printf-formatering och rapportgenerering” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Bemästra Linux-kommandoraden och Bash-skriptning, kan Ni uppgradera till CoddyKit PRO. Kursen i Bemästra Linux-kommandoraden och Bash-skriptning innehåller totalt 4 lektioner.
Vad lär jag mig i ”awk-funktioner, printf-formatering och rapportgenerering”?
Definiera egna funktioner och använd printf för att skapa välformaterade tabellrapporter från rådataströmmar. Ni övar på Bemästra Linux-kommandoraden och Bash-skriptning med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Bemästra Linux-kommandoraden och Bash-skriptning?
Du behöver inga förkunskaper. Utbildningen i Bemästra Linux-kommandoraden och Bash-skriptning på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.
Hur lång tid tar lektionen ”awk-funktioner, printf-formatering och rapportgenerering”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Bemästra Linux-kommandoraden och Bash-skriptning-lektionen?
Ja. Varje Bemästra Linux-kommandoraden och Bash-skriptning-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Poster, fält och anpassade avgränsare i awk
- Mönster, intervall och BEGIN-/END-block
- Aggregering med awk-arrayer och gruppering
- awk-funktioner, printf-formatering och rapportgenerering