First, it's important to differentiate between the following three
printf as a Bash builtin.
printf as an (Bash-)external executable, e.g. coreutil's
which printf and
man 1 printf).
printf(..) from the C standard libary (libc) (in my case its the GNU Project glibc implementation, see
man 3 printf
The first step is to find out whether the builtin or the external executable version is used when executing the command
printf '%s\n' foo bar. This can be found out using the
type Bash builtin on the particular shell prompt in use:
$ type printf
printf is a shell builtin
The Bash builtin
printf is documented in Bash Reference Manual - 4.2 Bash Builtin Commands:
While the Bash documentation doesn't have any explanation on
%d, it contains the following relevant information:
In addition to the standard
printf(1) formats, printf interprets the following extensions: [...]
On my system (Debian 11 bullseye)
man 1 printf shows that the
printf executable comes from GNU coreutils.
To run the command with that executable (instead of with the builtin), use any of these statements:
env printf '%s\n' foo bar
/usr/bin/printf '%s\n' foo bar
# full path to the printf *executable* found out via command 'which printf'
The coreutils executable
printf is documented in GNU Coreutils - 15.2
printf: Format and print data.
The coreutils documentation contains the following relevant information:
printf prints the format string, interpreting ‘
%’ directives and ‘
\’ escapes to format numeric and string arguments in a way that is mostly similar to the C ‘
printf’ function. See
printf format directives in The GNU C Library Reference Manual, for details. The differences are listed below. [...]
The coreutils documentation already provides additional explanations about
The referenced GNU C Library Reference Manual has the following sections relevant to
And finally: The GNU C Library is (also) an implementation of the the C POSIX library standard, more or less conforming to the specifications given therein.
POSIX is formally known (in its latest version) as POSIX.1-2017, and IEEE Std 1003.1-2017, and The Open Group Technical Standard Base Specifications, Issue 7. The specification provides the "official" rules on how
printf(..) is supposed to work "according to specification".
- POSIX.1-2017 Specification Home
- POSIX.1-2017 - Volume 'System Interfaces'
- POSIX.1-2017 - dprintf, fprintf, printf, snprintf, sprintf - print formatted output
[...] The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of POSIX.1-2017 defers to the ISO C standard. [...]
[...] The printf() function shall place output on the standard output stream stdout.
[...] Each of these functions converts, formats, and prints its arguments under control of the format. The format is a character string, beginning and ending in its initial shift state, if any. The format is composed of zero or more directives: ordinary characters, which are simply copied to the output stream, and conversion specifications, each of which shall result in the fetching of zero or more arguments. The results are undefined if there are insufficient arguments for the format. If the format is exhausted while arguments remain, the excess arguments shall be evaluated but are otherwise ignored. [...]
[...] In format strings containing the % form of conversion specification, each conversion specification uses the first unused argument in the argument list. [...]
[...] Each conversion specification is introduced by the '%' character [...], after which the following appear in sequence: [...] A conversion specifier character that indicates the type of conversion to be applied. [...]
The conversion specifiers and their meanings are:
d,i: The int argument shall be converted to a signed decimal in the style "[-]dddd". The precision specifies the minimum number of digits to appear; if the value being converted can be represented in fewer digits, it shall be expanded with leading zeros. The default precision is 1. The result of converting zero with an explicit precision of zero shall be no characters.
s: The argument shall be a pointer to an array of char. Bytes from the array shall be written up to (but not including) any terminating null byte. If the precision is specified, no more than that many bytes shall be written. If the precision is not specified or is greater than the size of the array, the application shall ensure that the array contains a null byte.
So apparently, to fully drill down to the definitions, the next step would be to look at the appropriate "ISO C Standard" (also known as "ANSI C") revision, formally specified in ISO/IEC 9899, e.g. in revision ISO/IEC 9899:2018, also known as C17. Finding the official, full specification for ISO C Standard revisions is not that easy, as this StackOverflow question shows.
But suffice to say, to find out the intended meaning and the actual behavior of "Bash's builtin
printf formatting options" for the more exotic varieties may require to drill down through several layers of implementations, abstractions, and specifications.
Keep in mind that different releases of these softwares may have varying available options and may change semantics of existing options. It's a best practice to refer to the manual version matching to the version in use. E.g. The GNU C Library Reference Manual provides versioned manual releases.