I want printf to recognize multi-byte characters when calculating the field width so that columns line up properly... I can't find an answer to this problem and was wondering if anyone here had any suggestions, or maybe a function/script that takes care of this problem.
Here's a quick and dirty example:
printf "## %5s %5s %5s ##\n## %5s %5s %5s ##\n" '' '*' '' '' "•" ''
>## * ##
>## • ##
Obviously, I want the result:
>## * ##
>## • ##
Any way to achieve this?
This is kind of late, but I just came across this, and thought I would post it for others coming across the same post. A variation to @ninjalj's answer might be to create a function that returns a string of a given length rather than calculate the required format length:
which outputs:
The best I can think of is:
You use the
*
width specifier to take the width as an argument, and calculate the width you need by adding the number of additional bytes in multibyte characters.Note that in GNU wc,
-c
returns bytes, and-m
returns (possibly multibyte) characters.Are these the only way? There's no way to do it with
printf
alone?Well with the example from ninjalj (thx btw), I wrote a script to deal with this problem, and saved it as
fprintf
in/usr/local/bin
:Usage:
fprintf "## %5s %5s %5s ##\n## %5s %5s %5s ##\n" '' '*' '' '' '•' ''
A few things to note:
*
(asterisk) values for formats because I never use them. I wrote this for me and didn't want to over-complicate things.%s
and%b
as they seem to be the only ones that are affected by this problem. Thus, if somehow someone manages to get a multi-byte unicode character out of a number, it may not work without minor modification.printf
(not some old-skooler UNIX hacker), feel free to modify, or use as is all!A language like python will probably solve your problems in a simpler, more controllable way...
A pure shell solution
Note that this still does not work in dash because dash has no locale support.
I will probably use GNU awk:
You can even write shell wrapper function called printf on top of awk to keep same interface:
and then override printf with simple function:
Test it: