printf Command: Tutorial & Examples

The reliable way to print formatted output in the shell — predictable where echo is full of surprises.

What It Is

printf prints text according to a format string, filling in placeholders with the arguments you give it. If you've written C, it's the same idea and nearly the same syntax. In the shell it's the grown-up replacement for echo: where echo's behaviour around newlines, escapes, and flags quietly differs between systems and shells, printf does exactly what its format string says, everywhere. Once you've been bitten by echo eating a backslash or printing -n as text, you switch to printf for anything that matters and never look back.

It exists both as a shell builtin and as a coreutils program (/usr/bin/printf), so it's on every Linux machine. It only writes to output — nothing destructive — which makes it safe to experiment with freely. This page will make you fluent in the handful of format codes that cover 95% of real use, and show you the one genuinely surprising thing it does that turns it from "fancy echo" into a small power tool.

Your First Look

The simplest useful form — print a string and a newline:

printf '%s\n' "hello"

hello

Two things are already different from echo, and both are deliberate. First, printf does not add a newline for you — you write \n yourself. That feels like extra work until you realise it means you're always in control: no surprise trailing newline, no missing one. Second, the format string and the data are separate%s is a slot, "hello" is what goes in it. That separation is the whole design, and it's what makes the next example click:

printf '%-10s|%5d\n' "name" 42

name      |   42

The format said: a left-justified string in a 10-wide field, a bar, then a number right-justified in a 5-wide field, then a newline. You get neat columns with zero effort — try that with echo.

How I Read It (the format string)

A printf format string is just text with two kinds of special sequences sprinkled in. Read it left to right and it's completely predictable:

  • %-codes are placeholders — each one consumes one argument and formats it. %s for a string, %d for an integer, %f for a float, and so on.
  • \-escapes are literal characters you can't easily type — \n newline, \t tab, \\ a real backslash.
  • Everything else prints verbatim.

So '%-10s|%5d\n' reads as: format-an-arg (string, left, width 10), a literal |, format-an-arg (integer, right, width 5), a newline. The numbers and dashes between % and the letter are the field spec — width, alignment, padding, precision — and that's where all the formatting power lives.

The Format Codes, Explained

The conversions you'll actually use (each consumes one argument):

  • %s — a string, printed as-is. Your workhorse.
  • %d / %i — a signed integer. printf '%d\n' 4242.
  • %f — a floating-point number, six decimals by default; %.2f rounds to two (printf '%.2f\n' 3.141593.14).
  • %x / %X — hexadecimal (printf '%x\n' 255ff); %o octal; %b binary (in some printfs).
  • %c — a single character. %% — a literal percent sign.

The field spec, written between % and the letter, controls layout:

  • Width%10s pads to 10 columns (right-justified by default); %-10s left-justifies.
  • Zero-pad%05d pads a number with leading zeros: printf '%05d\n' 4200042 (perfect for file_007.jpg-style names).
  • Precision%.2f (decimals) or %.3s (truncate a string to 3 chars).

And the escapes for characters you can't type literally: \n newline, \t tab, \r carriage return, \\ backslash, \xNN a byte by hex code.

The Magic: One Format String Recycles Over All Your Arguments

Here's the feature that makes printf quietly brilliant and that almost nobody learns: if you give more arguments than the format string has placeholders, printf reuses the format string, again and again, until it runs out of arguments. Watch:

printf '%s\n' one two three

one
two
three

One %s\n, three arguments — so the format runs three times, each on its own line. This turns printf into a tiny, reliable list-formatter. Need a two-column table from a flat list?

printf '%-8s %s\n' alice admin bob user carol admin

alice    admin
bob      user
carol    admin

The format has two slots, you fed it six arguments, so it looped three times and built a table. This recycling behaviour is why printf '%s\n' "${array[@]}" is the canonical, safe way to print a shell array one-per-line — it handles any number of elements with one format string. Once you see it, you start reaching for printf to format whole lists, not just single lines.

Reading It by Example

printf '%s' with no \n. Deliberately no newline — the cursor stays on the line. Useful for prompts (printf 'Continue? ') or building a line in pieces.

printf '%05d\n' 700007. Zero-padded numbers for sortable filenames or fixed-width IDs. A pile of frame_00001.pngframe_99999.png sorts correctly because of this.

printf '%.2f\n' "$price". Money and rounded values — %.2f guarantees two decimals where echo "$price" would print whatever was in the variable.

printf '%s\t%s\n' "$name" "$value" in a loop builds clean, tab-separated output that pastes straight into a spreadsheet or feeds awk.

printf '%(%Y-%m-%d)T\n' -1 (bash builtin) prints the current date with no date subprocess — a fast timestamp inside hot loops.

Cheat Sheet

  • printf '%s\n' "$x" — the safe echo replacement (no surprises)
  • printf '%s\n' "${arr[@]}" — print an array, one element per line
  • printf '%-20s %s\n' "$k" "$v" — aligned two-column output
  • printf '%05d\n' "$n" — zero-padded integer · printf '%.2f\n' "$f" — fixed decimals
  • printf '%x\n' "$n" — decimal → hex · printf '%d\n' 0xff — hex → decimal (255)
  • printf '%q\n' "$s" — shell-quote a string safely (bash) for reuse in scripts
  • printf '%b\n' 'a\tb' — interpret backslash escapes in the argument (the closest thing to echo -e)

How You'll Actually Use It

In day-to-day shell work, printf shows up the moment output needs to be exact: aligned columns in a status script, a value with no trailing newline, a zero-padded counter, money to two decimals, or a list printed safely one-per-line. The rule of thumb most scripters settle on: use echo for a quick throwaway message, use printf the instant formatting or portability matters — which, in anything you'll run twice, is most of the time. It pairs naturally with awk and sed in pipelines, and inside a bash loop it's how you assemble tidy, machine-readable lines.

Gotchas

  • No automatic newline. printf 'hi' leaves the cursor on the same line — add \n yourself. This is a feature (you're in control), but it surprises every newcomer once.
  • Too few arguments fills with empties/zeros. printf '%s %s\n' one prints one — the missing %s becomes empty (and a missing %d becomes 0), it does not error. Count your placeholders.
  • %-signs in data need escaping. To print a literal %, write %%. Passing user data as the format string (printf "$user_input") is a real bug — stray % codes will misformat or read garbage. Always do printf '%s' "$user_input".
  • Escapes live in the format string, not arguments. \n works inside the format; to interpret escapes in an argument you need %b. (echo -e blurs this; printf keeps it honest.)
  • Builtin vs /usr/bin/printf differ slightly. Your shell's builtin wins; the coreutils binary has its own quirks (e.g. number locale). Rarely matters, occasionally does.

History & Philosophy

printf is older than Unix shells caring about it — it's the C library's formatting function (1970s, Kernighan and Ritchie) lifted almost verbatim into the shell, which is why anyone who's written C feels instantly at home. It exists because echo was never standardised: different systems disagreed about whether echo -n suppressed the newline or printed -n, whether \t became a tab or stayed two characters. That ambiguity made portable scripts a minefield, and printf was the cure — one tool whose output depends only on the format string, not on which Unix you're standing on.

The deeper idea it teaches is the separation of format from data — describe the shape of your output once, then pour values into it. That principle runs from C to Python's f-strings to every templating system you'll ever touch, and printf is where most people first meet it in the shell. Learn its dozen format codes and you've learned a pattern you'll recognise for the rest of your career.

See Also

  • echo — the simpler, less predictable cousin printf replaces for real work
  • awk — has its own printf, for formatting inside data pipelines
  • sed — stream editing, often paired with printf-built input
  • cat — when you just want to dump a file unformatted
  • bash — where printf's array-recycling trick shines
  • shell — builtin vs external printf, and why it matters

Formatting output by hand is the easy part — knowing your servers are healthy is the hard part.

CleverUptime turns every server's raw numbers into plain-language status you don't have to format or parse. See your own server's health in 30 seconds, no signup.