bash printf – Formatting Not Working

bashprintf

For example, the \c format does not work.
I'm input printf "ABC\ctest" to bash console and result;

ABC\ctest

Considering the \c format's property, the expected output should be in the form of just ABC.

Nor did I find a proper source that detailed the use of the printf command on bash. Also, as in the above example, the properties on the man page specified for the printf command do not work correctly.

Please show me a source on bash that explains the printf command in detail. Because I'm so confused right now.

Best Answer

printf 'ABC\ctest'

You've hit upon one of the unspecified parts of the printf command, whose behaviour varies from implementation to implementation. You're putting the \c in the wrong place.

If you read the Single Unix Specification's description of printf carefully, you will see that \c is not listed in the list of escape sequences that are defined for the format string (the first argument to the command). Rather, it is defined as an extra escape sequence that is recognized when given in an argument string that is to be formatted by the %b format specifier.

In other words:

  • printf '%b\n' 'ABC\ctest' has a well specified behaviour. The \c causes everything remaining (including the newline in the format string) to be ignored.
  • printf '%s\n' 'ABC\ctest' has a well specified behaviour. The \c is not an escape sequence in the first place.
  • printf '\c' does not have a well specified behaviour. The SUS is simply silent upon what \c is, not listing it as an escape sequence but also not saying in its File Format Notation section that such a sequence is never an escape sequence.

How different shells behave in response to this non-conformant format string varies quite significantly. Here are the Debian Almquist, Bourne Again, FreeBSD Almquist, Korn '93, and Z shells' reactions (with %s showing where no newlines have been emitted):

% dash -c "printf 'ABC\ctest\n'"
ABC\ctest
% bash -c "printf 'ABC\ctest\n'"
ABC\ctest
% sh -c "printf 'ABC\ctest\n'"
ABC%
% ksh93 -c "printf 'ABC\ctest\n'"
ABCest
% zsh -c "printf 'ABC\ctest\n'"
ABC%
%

The builds of the MirBSD Korn and PD Korn shells that I have do not have a printf built-in command. The FreeBSD non-built-in printf does this:

% /usr/bin/printf 'ABC\ctest\n'
ABC%
%

Adding to the fun is that the doco for the various shells is sometimes highly misleading and even sometimes downright erroneous. For examples:

  • The Z shell doco only recently started to give a correct description of what \c does, and lists it (via its doco for echo) as an escape sequence allowed in format strings. (It was incorrect until 2017, the doco neither agreeing with the SUS nor describing what the Z shell actually did.)
  • The Korn '93 shell doco gives a description that is in line with the SUS, but it is not (as can be seen in the aforegiven) what it actually does when \c is in the format specifier. It, too, documents \c as an escape sequence for the format string. Its behaviour is clearly a bug.
  • The doco for the Bourne Again shell and the doco for the Debian Almquist shell give a description of \c that matches the SUS and explicitly list it in relation to %b (in the case of the Bourne Again shell more clearly than it does now up until 2016) and not in a general list of escape sequences for printf format specifiers. These shells do not provide this as an extension to the standard.
  • The FreeBSD Almquist shell doco defers to the FreeBSD external printf command manual, whose description of \c is in line with the SUS. It explicitly lists it as an escape sequence allowed in format strings, and its actual behaviour is as documented in the user manual.

The FreeBSD Almquist shell and (recent) Z shell are the only shells, here, that both document allowing \c as an escape sequence in format strings (an extension to what is defined by the standard) and actually behave as they are documented.

Ironic further reading

Related Question