Linux Basics: Format Output Explicitly with GNU printf
Predictable shell output needs a fixed format string and data passed as separate arguments. This example invokes the external GNU printf through env, making the implementation explicit even when Bash has a builtin with the same name.
Prepare a scratch directory
Tested on Linux with GNU coreutils 9.7 and GNU Bash 5.2.37. You need the named runtime, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. The script creates a separate temporary fixture directory and removes only that directory on exit. It does not operate on your existing files.
Keep using the same terminal. Stop if setup fails, before saving the source:
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1Run the example
Save this as demonstrate-gnu-printf.sh:
#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
fixture_dir="$(mktemp -d)"
trap 'rm -rf -- "$fixture_dir"' EXIT
cd -- "$fixture_dir"
printf 'Fixed-width table:\n'
env printf '%-8s %04d\n' alpha 7 beta 23
printf 'Untrusted-looking text treated as data:\n'
value='%s has a backslash: \n'
env printf '%s\n' "$value"
printf 'Explicit escape interpretation:\n'
env printf '%b' 'left\tright\n' | cat -T
printf 'Literal percent: '
env printf '%d%%\n' 50
env printf '%s\n' "$value" > value.txt
test "$(cat value.txt)" = "$value"Run it:
bash demonstrate-gnu-printf.shObserved output:
Fixed-width table:
alpha 0007
beta 0023
Untrusted-looking text treated as data:
%s has a backslash: \n
Explicit escape interpretation:
left^Iright
Literal percent: 50%Read the result
The format repeats as needed for the extra arguments, producing two table rows. %s emits the supplied value literally, including percent signs and backslash characters. %b deliberately interprets backslash escapes in its argument; cat -T makes the resulting tab visible. %% emits one percent sign from the format itself.
Apply it carefully
Keep externally supplied text out of the format string. Prefer %s for arbitrary text, and use %b only when escape interpretation is intended. Numeric formatting can have locale-dependent behavior; the fixture selects C. Bash’s builtin and the external GNU utility have overlapping but not identical options and conversions, which is why env printf is used for the demonstrated formatting operations. Formatting is not escaping for HTML, SQL, or a shell command.
The official reference describes the API and its options. The checks above cover the specific fixture, not every possible input or environment.
Clean up
Remove the source and then the empty practice directory:
rm -- demonstrate-gnu-printf.sh
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dirIf the directory is not empty, inspect the remaining files rather than deleting unknown contents.
Acknowledgements
This post was created with assistance from AI.