Bash printf Command

Typically, when writing bash scripts, we use echo to print to the standard output. echo is a simple command but is limited in its capabilities.
To have more control over the formatting of the output, use the printf command.

The printf command formats and prints its arguments, similar to the C printf() function.

printf Command

printf is a shell builtin in Bash and in other popular shells like Zsh and Ksh. There is also a standalone /usr/bin/printf binary, but the shell built-in version takes precedence. We will cover the Bash builtin version of printf.

The syntax for the printf command is as follows:

printf [-v var] format [arguments]

The -v option tells printf not to print the output but to assign it to the variable.

The format is a string which may contain three different types of objects:

  • Normal characters that are simply printed to the output as-is.
  • Backslash-escaped characters which are interpreted and then printed.
  • Conversion specifications that describe the format and are replaced by the values of respective arguments that follow the format string.

The command accepts any number of arguments. If more arguments than format specifiers are provided, the formatstring is reused to consume all of the arguments. If fewer arguments than format specifiers are supplied, the extra numeric-format specifiers are set to zero value while string-format specifiers are set to null string.

Below are a few points to consider when passing arguments the printf command:

  • The shell will substitute all variables, wildcard matching, and special characters before passing the arguments to the printf command.
  • When using single quotes '' the literal value of each character enclosed within the quotes will be preserved. Variables and commands will not be expanded.

A typical example of using printf looks like:

printf "Open issues: %s\nClosed issues: %s\n" "34" "65"
Open issues: 34
Closed issues: 65

The string Open issues: %s\nClosed issues: %s\n is the format while “34” and “65” are arguments. The format string contains two newline characters (\n) and two format specifiers (%s) that are replaced with the arguments.

The printf command doesn’t add a newline character (\n) at the end of the line.

Backslash-escaped Characters

The backslash-escaped characters are interpreted when used in the format string or in an argument corresponding to a %bconversion specifier. Here is a list of the most common escape characters:

  • \\ – Displays a backslash character.
  • \b – Displays a backspace character.
  • \n – Displays a new line.
  • \r – Displays a carriage return.
  • \t – Displays a horizontal tab.
  • \v – Displays a vertical tab.

Conversion specifications

A conversion specification takes the following form:

%[flags][width][.precision]specifier

Each conversion specification stars with the percent sign (%), includes optional modifiers and ends with one of the following letters that represent the data type (specifier) of the corresponding argument: aAbcdeEfgGioqsuxX.

Type conversion specifier

The type conversion specifier is a character that specifies how to interpret the corresponding argument. This character is required, and it is placed after the optional fields.

Below is a list showing all type conversions and what they do:

  • %b – Print the argument while expanding backslash escape sequences.
  • %q – Print the argument shell-quoted, reusable as input.
  • %d, %i – Print the argument as a signed decimal integer.
  • %u – Print the argument as an unsigned decimal integer.
  • %o – Print the argument as an unsigned octal integer.
  • %x, %X – Print the argument as an unsigned hexadecimal integer. %x prints lower-case letters and %X prints upper-case.
  • %e, %E – Print the argument as a floating-point number in exponential notation. %e prints lower-case letters and %Eprints upper-case.
  • %a, %A – Print the argument as a floating-point number in hexadecimal fractional notation. %a prints lower-case letters and %A prints upper-case.
  • %g, %G – Print the argument as a floating-point number in normal or exponential notation, whichever is more appropriate for the given value and precision. %g prints lower-case letters and %G prints upper-case.
  • %c – Print the argument as a single character.
  • %f – Print the argument as a floating-point number.
  • %s – Print the argument as a string.
  • %% – Print a literal % symbol.

An unsigned number represents zero and positive numbers, while a signed number represents negative, zero, and positive numbers.

The following command prints the number 100 in three different number systems:

printf "Decimal: %d\nHex: %x\nOctal: %o\n" 100 100 100
Decimal: 100
Hex: 64
Octal: 144

Flags directive

Flags are the first optional modifiers and are used to set the justification, leading zeros, prefixes, etc.

Here are the most common ones:

  • - – Left align the printed text within the field. By default, the text is right-aligned.
  • + – Prefix the numbers with a + or - signs. By default, only negative numbers are prefixed with a negative sign.
  • 0 – Pads numbers with leading zeros rather than space.
  • blank `- Prefix the positive numbers with a blank space and negative numbers with a minus (-`).
  • # – An alternative format for numbers.

Width directive

The width directive filed is placed after any flag characters and specifies the minimum number of characters the conversion should result in.

If the outputted text width is less than the specified width, it’s padded with spaces. The width can be specified as a non-negative decimal integer or an asterisk (*).

Here is an example:

printf "%20s %d\n" Mark 305

%20s means set the field at least 20 characters long. Blanks are added before the text because, by default, the output is right-justified. To align the text to left, use the - flag (%-20s).

      Mark 305

When an asterisk (*) is used as a width directive, then the width of the conversion field is set by a width argument that precede the argument that’s being formatted.

In the example below we’re setting the width to 10:

printf "%0*d" 10 5

0 is a flag that pads the number with leading zeros instead of blanks. The output text will have at least 10 characters:

0000000005

Precision directive

The .precision modifier consists of a dot (.) followed by a positive integer or asterisk (*) that depending on the specifier type, sets the number of string or digit characters or the number of decimal places to be printed.

The precision has the following effect:

  • If the conversion type is an integer, the precision specifies the minimum number of digits to be printed. If the number of digits in the argument is less than precision, leading zeros are printed.
  • If the conversion type is a floating-point, the precision specifies the number of digits that follow the decimal-point character. The default precision is 6.
  • If the conversion type is a string, the precision specifies the maximum number of characters to be printed. If the number of characters in the argument is greater than precision, the excess characters are truncated.

Here is an example showing how to round a floating-point number to 3 decimals:

printf "%.3f" 1.61803398
1.618

When precision is set to an asterisk (*), its value is set by the precision argument that precede the argument that’s being formatted.

printf "%.*f" 3 1.61803398
1.618

Conclusion

The printf command takes a format and arguments and prints a formatted text.

If you have any questions or feedback, feel free to leave a comment.

Leave a Reply