Home / Alt manpages / printf(1)

  • printf(1)
  • User command
  • linux

Use GNU printf for Predictable Shell Output

GNU printf exists because echo disagrees with itself across systems, and a fixed format string does not. This covers repeated arguments, numeric formatting, escapes, and the one trap that can make a variable's contents get interpreted as formatting instructions. The examples use GNU coreutils 9.4, package version 9.4-3ubuntu6.3.

Allow about ten minutes. You need a shell and a normal user account. These examples only write to standard output, so no sudo, and nothing here touches files or services. Use /usr/bin/printf when you want to test the external GNU program specifically, since a shell may provide its own builtin with a different set of extensions.

1. Confirm which printf you are using

Check the command path and installed version before putting any syntax into a script:

$ command -v printf
/usr/bin/printf
$ /usr/bin/printf --version | head -n 1
printf (GNU coreutils) 9.4

command -v may report a shell builtin rather than a path, which is normal. For portable shell scripts, printf usually beats echo because echo implementations disagree about options and backslash escapes. This guide uses the explicit path throughout to keep the GNU behaviour unambiguous.

Checkpoint

If /usr/bin/printf --version does not report GNU coreutils, stop and read that system's manual before copying GNU-specific examples such as %q.

2. Print literal text and values

The first argument is the format. A %s conversion consumes the next argument as text, and \n adds a newline:

$ /usr/bin/printf 'user=%s\nstatus=%s\n' 'Ada' 'ready'
user=Ada
status=ready

Keep the format in single quotes when it contains backslashes or dollar signs, and quote values separately. That keeps whitespace and shell metacharacters in a value from changing how the shell parses the command.

The format also gets reused: give three values against one conversion and GNU printf repeats the format until every argument is consumed:

$ /usr/bin/printf 'item=%s\n' 'red' 'green' 'blue'
item=red
item=green
item=blue

With too few arguments, text conversions get an empty string and numeric conversions get zero. That default can hide a missing variable, so make required inputs explicit in a script rather than trusting the output.

3. Format numbers and columns

Use numeric conversions when the input is actually a number: %d for decimal integers, %f for floating point, %x for hexadecimal:

$ /usr/bin/printf 'count=%d hex=%x rate=%.2f%%\n' 27 27 3.5
count=27 hex=1b rate=3.50%

The doubled %% prints one literal percent sign, and .2 limits the fractional part shown here. GNU printf converts arguments to the requested type, but invalid numeric input is an error condition worth checking for in a script.

A field width pads output to a minimum size. A star takes the width from the next argument, useful when the width itself is calculated:

$ /usr/bin/printf '%*s %s\n' 8 'ok' 'connected'
      ok connected

Padding is spaces by default, and a negative width left-aligns the field. Keep the format and width under your own control; never treat an untrusted value as a format string.

4. Use escapes deliberately

GNU printf interprets escapes in the format itself, including \t for a tab, \n for a newline, and hexadecimal or Unicode forms. Fine for small, known strings:

$ /usr/bin/printf 'name\tstate\n%s\t%s\n' 'worker-1' 'ready'
name	state
worker-1	ready

For a value that itself contains escapes, use %b, which interprets backslash escapes in that value, so only reach for it when the value is trusted or built deliberately by your own script:

$ /usr/bin/printf '%b\n' 'first\nsecond'
first
second

Warning

Do not use %b to print arbitrary user input. A value containing \c can suppress the rest of the output, and other escapes can create control characters. For ordinary data, %s is the safer choice.

5. Quote a value for later shell input

GNU's %q conversion prints a value in a form reusable as shell input, useful for diagnostics or inspecting a value without losing its spaces:

$ /usr/bin/printf 'value=%q\n' 'two words; keep this'
value='two words; keep this'

That output is shell-quoted, not a general-purpose data format. Do not pass untrusted generated text to eval just because it came from %q; prefer arrays and direct command arguments when a script needs to run something. The conversion is also a GNU extension, so do not assume it exists elsewhere.

Common traps

  • Variable in the format position. Never put a variable there if it might contain a percent sign:
$ message='100% ready'
$ /usr/bin/printf '%s\n' "$message"
100% ready

The fixed %s format prints the value literally. printf "$message\n" instead would let the value's own content become formatting instructions.

Redirection changes files before printf runs. This is destructive if the destination already holds something useful:

$ /usr/bin/printf '%s\n' 'new line' > output.txt

Fine for a new file. To append instead, use >>. To replace a file safely, write a new temporary file, check it, then rename it into place in the same directory. If you accidentally truncate a file, stop writing to it and restore from your normal backup; printf cannot undo shell redirection.

Done means

  • Implementation confirmed. You know whether the shell selected a builtin or GNU coreutils 9.4.
  • Fixed format, quoted values. Especially for data containing spaces or percent signs.
  • Argument reuse understood. A format repeats for extra arguments, and missing arguments become empty text or zero.
  • %b and %q used with care. %b only for deliberately trusted escapes, %q treated as GNU-specific shell quoting.
  • Redirection target checked before output was allowed to replace or append to a file.