2

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.

testter
  • 1,410
  • What shell are you using? – Paulo Tomé Dec 23 '19 at 16:47
  • 1
    The man page that you are reading is probably for POSIX printf whereas the behavior you see in the terminal is likely your shell's builtin printf implementation. The former may be present on your system as /usr/bin/printf for example so see if /usr/bin/printf "ABC\ctest" gives the expected behavior. – steeldriver Dec 23 '19 at 17:02
  • @steeldriver The behavior he is expecting is not POSIX compliant. He may be on linux where a non-compliant /usr/bin/printf with a related non-compliant man page exists, that incorrectly mentions and implements '\c' for the format string. – schily Feb 08 '20 at 09:21

2 Answers2

9
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

JdeBP
  • 68,745
  • Thank you seperate your time for my question. – testter Dec 23 '19 at 19:47
  • BTW: ksh93 converts \ct in a format string into the character 0x14 - looks like control-t. And thank you for mentioning that printf is as problematic as echo as a result of implementors that ignore POSIX. – schily Jan 27 '20 at 11:59
5

It is necessary to expand backslash escape sequences in the corresponding argument. As stated in here:

\c  Terminate output similarly to the \c escape used by echo -e. printf produces no additional output after coming across a \c escape in a %b argument.
$ printf "%b\n" "ABC\chi"
ABC
Paulo Tomé
  • 3,782