What characters need to be escaped when using the printf command?
In the format argument of printf
, only the %
and \
characters are special (no, "
is not special and \"
is unspecified per POSIX).
But, two important notes.
In most
printf
implementations¹, it's the byte values for\
and%
that are special and the POSIX specification could even be interpreted as requiring it as it requires theprintf
utility to be an interface to theprintf(3)
C function and notwprintf(3)
for instance (like it requires%.3s
to truncate to 3 bytes and not 3 characters).In some character encodings including BIG5 and GB18030, there are hundreds of characters that contain the encoding of backslash, and to escape those for
printf
, you'd need to insert a\
before each0x5c
byte within the encoding of those characters!For instance in BIG5-HKSCS, as used for instance in the
zh_HK.big5hkscs
(Hong Kong) locale, all ofĚαжふ㘘㙡䓀䨵䪤么佢俞偅傜兝功吒吭园坼垥塿墦声娉娖娫嫹嬞孀尐岤崤幋廄惝愧揊擺暝枯柦槙檝歿汻沔涂淚滜潿瀙瀵焮燡牾狖獦珢珮琵璞疱癧礒稞穀笋箤糭綅縷罡胐胬脪苒茻莍蓋蔌蕚螏螰許豹贕赨跚踊蹾躡鄃酀酅醆鈾鎪閱鞸餐餤駹騱髏髢髿鱋鱭黠﹏
contain byte 0x5c (which is also the encoding of\
).With most
printf
implementations, in that locale,printf 'αb'
doesn't outputαb
but byte0xa3
(the first byte of the encoding ofα
) followed by the BS character (the expansion of\b
).$ LC_ALL=zh_HK.big5hkscs luit $ locale charmap BIG5-HKSCS $ printf 'αb' | LC_ALL=C od -tx1 -tc 0000000 a3 08 243 \b 0000002
Best is to avoid using (and even installing / making available) those locales as they cause all sorts of bugs and vulnerabilities of that sort.
Some
printf
implementations support options, and even those that don't are required to support--
as the option delimiter. Soprintf --
won't output--
but likely report an error about a missing format argument. So if you can't guarantee your format won't start with-
, you have to use the--
option delimiter:printf -- "$escaped_format" x y...
In any case, if you want to print arbitrary strings, you'd use:
printf '%s\n' "$data" # with terminating newline
printf %s "$data" # without
There's no character that is special in the string passed to %s
(though note that with the exception of the printf
builtin of zsh
, you can't pass the NUL character in any of printf
arguments).
Note that while the canonical way to enter a literal \
is with \\
and a literal %
with %%
, on ASCII-based systems, you can also use \134
and \45
and with some printf
implementations \x5c
, \x25
, or \x{5c}
, \x{25}
, or (even on non-ASCII systems): \u005c
, \u0025
or \u{5c}
, \u{25}
.
¹ yash
's printf
builtin being the only exception I am aware of.
From the manual:
$ man printf
...
printf FORMAT [ARGUMENT]...
...
FORMAT controls the output as in C printf. Interpreted sequences are:
This lists several interpreted sequences. The following are those where the character itself needs to be escaped.
\" double quote
\\ backslash
%% a single %
I tested these three in bash
, and they behaved as expected. As per man bash
, this implementation of printf
uses the "standard printf(1) format specifications" as above, in addition to a few more that aren't relevant here.
However, other shells such as zsh
implement printf
slightly differently. Here, the double quote shouldn't be escaped.
$ printf '"'
"
$ printf '\"'
\"