Während echo für schnelle Ausgaben reicht, ist printf das Werkzeug für ernsthafte Shell-Skripte: Es nimmt einen Format-String und beliebig viele Argumente entgegen, fügt sie nach klar definierten Regeln zusammen und verhält sich auf jeder POSIX-Shell identisch. Wer aus C kommt, kennt das Prinzip — %s, %d, %f und Konsorten funktionieren in Bash ganz genauso.
Was printf macht
printf schreibt Text auf die Standardausgabe — aber im Gegensatz zu echo nach einem Format-String, der bestimmt, wie die übergebenen Argumente dargestellt werden. Das Modell ist direkt aus der C-Standardbibliothek entliehen und damit der Shell-Programmierung vertraut, sobald man einmal eine Programmiersprache mit printf gesehen hat.
printf '%s ist %d Jahre alt\n' "Max" 42Max ist 42 Jahre altDrei wichtige Eigenschaften unterscheiden printf grundlegend von echo:
- Kein automatisches Newline. Wer eine neue Zeile will, schreibt
\nselbst in den Format-String. Das wirkt zunächst unbequem, gibt aber volle Kontrolle. - Escape-Sequenzen werden immer interpretiert — kein
-e-Flag nötig.\n,\t,\\funktionieren direkt. - Portabel. Die POSIX-Spezifikation für
printfist eng definiert; das Verhalten ist auf Bash, Zsh, Dash, Ksh und allen seriösen Shells identisch.
printf vs. echo
Beide Werkzeuge geben Text aus — aber für ernsthafte Skripte ist die Wahl klar.
| Aspekt | echo | printf |
|---|---|---|
| Newline am Ende | automatisch (außer mit -n) | nur wenn explizit \n |
| Escape-Sequenzen | nur mit -e (Bash), in Zsh standardmässig | immer interpretiert |
| Portabilität | uneinheitlich (Bash/Zsh/Dash/BSD verhalten sich unterschiedlich) | POSIX-spezifiziert, überall gleich |
| Format-Specifier | keine | %s, %d, %f, %x und mehr |
| Width und Precision | nicht möglich | %-20s, %.3f, %5d |
Argumente mit - | werden teilweise als Optionen interpretiert | Argumente nach dem Format sind sicher |
| In Variable schreiben | nur über Subshell $(...) | direkt mit printf -v (Bash) |
Format-Specifier
Ein Format-Specifier beginnt mit % und beschreibt, wie ein Argument dargestellt wird. Zwischen % und dem Typbuchstaben können optional Flags, Width und Precision stehen.
| Specifier | Bedeutung | Beispiel-Eingabe | Beispiel-Ausgabe |
|---|---|---|---|
%s | String | Hallo | Hallo |
%d / %i | Integer (dezimal) | 42 | 42 |
%f | Gleitkommazahl, Standard 6 Nachkommastellen | 3.14 | 3.140000 |
%e | wissenschaftliche Notation | 12345.6 | 1.234560e+04 |
%g | kompakteste sinnvolle Darstellung | 0.000123 | 0.000123 |
%x / %X | Hexadezimal (klein/groß) | 255 | ff / FF |
%o | Oktal | 8 | 10 |
%c | einzelnes Zeichen | A | A |
%b | String mit Escape-Interpretation im Argument | Zeile\nNeu | zwei Zeilen |
%q | shell-quoted (sicheres Re-Parsing) | Hello World | Hello\ World |
%% | literales Prozentzeichen | — | % |
printf '%s = %d (hex: %x, oct: %o)\n' "Wert" 255 255 255
printf 'Pi ungefähr %f, kompakt %g\n' 3.14159 3.14159
printf 'Rabatt %d%% auf alles\n' 20Wert = 255 (hex: ff, oct: 377)
Pi ungefähr 3.141590, kompakt 3.14159
Rabatt 20% auf allesWidth und Precision
Zwischen % und dem Typbuchstaben kann eine Mindestbreite und eine Genauigkeit stehen. Damit lassen sich Tabellen exakt ausrichten.
| Form | Wirkung |
|---|---|
%5d | Integer, mindestens 5 Zeichen breit, rechts-bündig (mit Leerzeichen aufgefüllt) |
%-10s | String, mindestens 10 Zeichen breit, links-bündig (Minus-Flag) |
%05d | Integer, mit führenden Nullen auf 5 Stellen aufgefüllt |
%.3f | Float mit genau 3 Nachkommastellen |
%10.3f | Float, gesamt 10 Zeichen breit, davon 3 nach dem Komma |
%-20s%5d | Kombination: 20 Zeichen links-bündiger String, danach 5 Zeichen rechts-bündige Zahl |
%*d | Width wird als Argument übergeben (dynamisch) |
printf '%-15s %5s %8s\n' "Name" "Alter" "Saldo"
printf '%-15s %5d %8.2f\n' "Anna" 32 1234.50
printf '%-15s %5d %8.2f\n' "Maximilian" 45 99.95
printf '%-15s %5d %8.2f\n' "Bo" 7 0.10Name Alter Saldo
Anna 32 1234.50
Maximilian 45 99.95
Bo 7 0.10Mit dem dynamischen Width-Parameter * lässt sich die Breite zur Laufzeit bestimmen — das Argument unmittelbar vor dem Wert wird als Breite gelesen.
breite=12
printf '%*s|\n' "$breite" "rechts" rechts|Escape-Sequenzen
Im Format-String werden Backslash-Escapes immer interpretiert — anders als bei echo ist kein Flag nötig.
| Sequenz | Bedeutung |
|---|---|
\n | Zeilenumbruch (Newline) |
\t | horizontaler Tabulator |
\r | Carriage Return |
\\ | literaler Backslash |
\" | literales doppeltes Anführungszeichen |
\a | Bell (akustisches Signal) |
\xHH | Byte mit hexadezimalem Wert HH |
\NNN | Byte mit oktalem Wert NNN |
\uHHHH | Unicode-Codepoint (Bash-builtin, 4 Hex-Stellen) |
\UHHHHHHHH | Unicode-Codepoint (Bash-builtin, 8 Hex-Stellen) |
printf 'A=\x41 Pi=π Euro=€\n'
printf 'Pfad:\t/etc/hosts\nMode:\t0644\n'A=A Pi=π Euro=€
Pfad: /etc/hosts
Mode: 0644Reuse von Format-String
Eines der nützlichsten Features: Wenn mehr Argumente übergeben werden als Format-Specifier vorhanden sind, wird der Format-String wiederholt, bis alle Argumente verbraucht sind.
printf '%s\n' a b c da
b
c
dStatt eine Schleife zu schreiben, übergibst du einfach alle Werte. Das funktioniert genauso mit mehreren Specifiern — printf arbeitet dann den Format-String pro Specifier-Gruppe ab.
printf '%-10s %d\n' "Anna" 32 "Bert" 45 "Carla" 28Anna 32
Bert 45
Carla 28Ideal für Listen aus Arrays. printf '%s\n' "${arr[@]}" druckt jeden Eintrag in eine eigene Zeile — ohne Schleife, ohne for.
Praxis-Patterns
Tabelle formatieren
Mit %-20s als links-bündigem String und %5d als rechts-bündigem Integer richtest du Spalten exakt an einer Pixelkante aus — unabhängig davon, wie lang die einzelnen Werte sind. Das ist der zuverlässigste Weg, eine lesbare Tabelle ohne externe Tools wie column zu bauen.
printf '%-20s %5s\n' "Service" "Port"
printf '%-20s %5d\n' "ssh" 22
printf '%-20s %5d\n' "http" 80
printf '%-20s %5d\n' "https" 443Service Port
ssh 22
http 80
https 443CSV erzeugen
Anders als echo mit interpolierten Variablen umgeht printf Probleme mit Sonderzeichen oder Werten, die mit - beginnen. Achtung: Enthält ein Wert selbst ein Komma oder Anführungszeichen, brauchst du echtes CSV-Quoting — printf kümmert sich nicht um RFC-4180-Escaping.
printf '%s,%s,%d\n' "Anna" "anna@example.com" 32Anna,anna@example.com,32In Variable schreiben mit -v
In Bash schreibt printf -v VARNAME ... direkt in eine Variable — ohne Subshell, ohne Performance-Overhead von $(...).
printf -v greeting 'Hallo, %s!' "Welt"
echo "$greeting"Hallo, Welt!Log-Zeile mit Timestamp
Die Kombination aus date-Substitution und %-5s für das Level erzeugt strukturiertes, gleichmäßig ausgerichtetes Logging — gut lesbar im Terminal und problemlos mit awk oder grep auswertbar. Das %-5s sorgt dafür, dass INFO, WARN und ERROR alle gleich breit ausgegeben werden.
printf '[%s] %-5s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "INFO" "Backup gestartet"[2026-05-05 14:32:01] INFO Backup gestartetJSON manuell zusammenstellen
Für kleine, kontrollierte Fälle (für komplexes JSON nimm jq):
name="Anna"
age=32
printf '{"name":"%s","age":%d}\n' "$name" "$age"{"name":"Anna","age":32}Besonderheiten
Builtin oder Binary — type -a printf zeigt es
In Bash ist printf ein eingebauter Befehl; daneben existiert das eigenständige Programm /usr/bin/printf aus den GNU Coreutils. Mit type -a printf listest du beide auf. Im Alltag spielt das selten eine Rolle, aber subtile Unterschiede gibt es: Das Builtin kennt printf -v (in Variable schreiben), das Binary nicht. Umgekehrt akzeptiert das Binary die Option --, das Builtin nicht. Mit command printf ... oder dem absoluten Pfad erzwingst du das externe Programm.
%b interpretiert Escapes im Argument — gefährlich mit User-Input
Während %s ein Argument unverändert ausgibt, interpretiert %b Backslash-Sequenzen innerhalb des Arguments. printf '%b\n' 'Zeile\nNeu' erzeugt zwei Zeilen. Das ist praktisch, wenn du Escapes in Variablen aktiv interpretieren willst — aber gefährlich, sobald die Werte aus unkontrollierter Quelle stammen. Ein Angreifer kann mit \e[2J den Bildschirm löschen oder mit \xHH beliebige Bytes einschleusen. Für fremden Input gilt: immer %s, nie %b.
Locale beeinflusst Float-Output — Komma vs. Punkt
printf '%f\n' 3.14 gibt unter LC_NUMERIC=de_DE.UTF-8 tatsächlich 3,140000 aus — mit Komma als Dezimaltrenner. Das bricht Skripte, die die Ausgabe weiterverarbeiten oder in Dateien schreiben, die später woanders gelesen werden. Für reproduzierbare numerische Ausgabe immer LC_NUMERIC=C printf ... oder export LC_NUMERIC=C am Skriptanfang verwenden. Das gilt auch für awk, bc und alle anderen Werkzeuge, die Zahlen formatieren.
%q für sicheres Quoting in generierten Skripten
printf '%q\n' "Hallo Welt mit 'Sonderzeichen'" gibt einen String aus, der von der Shell wieder eingelesen werden kann, ohne dass Sonderzeichen Schaden anrichten. Ideal, wenn du Skripte oder Befehle dynamisch zusammenbaust und an eval, bash -c oder eine Datei weitergibst. %q ist das Bash-Pendant zu shlex.quote() aus Python — sicheres Quoting für die Shell.
Reuse-Mechanismus ersetzt for-Schleifen
Wenn mehr Argumente als Specifier vorhanden sind, wird der Format-String wiederholt. printf '%s\n' "${array[@]}" druckt jedes Element des Arrays in eine eigene Zeile — ohne for, ohne Indexierung. Das ist nicht nur kürzer, sondern auch deutlich schneller als eine Schleife mit einzelnen echo-Aufrufen, weil nur ein einziger printf-Aufruf nötig ist. Auch mit mehreren Specifiern: printf '%s=%s\n' key1 val1 key2 val2 key3 val3 erzeugt drei Zeilen.
printf akzeptiert kein -- als Argumentterminator
Das Builtin printf kennt kein -- zum Beenden der Optionen. Argumente, die direkt nach dem Format-String stehen und mit - beginnen, können in Sonderfällen als Option missinterpretiert werden — vor allem, wenn der Format-String selbst leer oder unsauber ist. Sicherer Stil: Format-String immer in einfache Anführungszeichen einschließen und Werte explizit als Argumente übergeben. printf '%s\n' "$value" ist auch dann sicher, wenn $value mit -n oder -e beginnt — das ist genau der Vorteil gegenüber echo.
Weiterführende Ressourcen
Externe Quellen
- printf – POSIX specification (man7.org) — POSIX-Standardverhalten und alle Specifier
- GNU Coreutils: printf invocation — Ausführliche Doku zum Coreutils-Binary
- Bash Reference Manual: printf builtin — Bash-spezifische Erweiterungen wie
-v - Why is printf better than echo? – Unix StackExchange — Klassische Diskussion zur Portabilität
- POSIX Format Strings – pubs.opengroup.org — Die formale C-Spezifikation, auf der Shell-
printfbasiert
Verwandte Artikel
- echo – Text auf der Standardausgabe ausgeben — Der schlankere Bruder von printf
- cat – Dateien anzeigen und verbinden — Dateien direkt ausgeben
- sed – Stream-Editor für Text — Suchen und Ersetzen in Streams
- awk – Felder und Spalten verarbeiten — Mächtiges Format-Tool mit eigenem printf
- Linux Shell-Scripting — Grundlagen der Bash-Skripte