In bash scripts I like to use printf "%-20s" "some string"
to create columns that line up. That works great with regular text, but not really for multi-byte unicode, nor if using any kind of terminal decoration.
Works great:
for i in string longer_string Some_kind_of_monstrosity ; do
printf "%-20s" $i ; echo " OK"
done
Everything is reasonably well lined up:
string OK
longer_string OK
Some_kind_of_monstrosity OK
However - it doesn't work very well with multi-byte unicode or colour codes:
printred () { tput setaf 1; printf %b "$*"; tput sgr0; }
printf "%-20s" test ; echo " NOK"
printf "%-20s" $(printred RED) ; echo " NOK"
printf "%-20s" "★★★★" ; echo " NOK"
It looks like both the bash builtin printf
and the coreutils/printf simply count the number of bytes in the string, rather than how many character that will be visible on the output:
test NOK
RED NOK
★★★★ NOK
Is there a way to achieve this nicely in bash? (I'm using bash 5.0.17, but I'm not averse to using some other tool.)
I have found a potential answer:
printred () { tput setaf 1; printf %b "$*"; tput sgr0; }
/bin/printf "%s" test ; tput hpa 20; echo " OK"
/bin/printf "%s" $(printred RED) ; tput hpa 20; echo " OK"
/bin/printf "%s" "some kind of over-long line" ; tput hpa 20; echo " OK"
/bin/printf "%s" "★★★★" ; tput hpa 20; echo " OK"
This results in everything neatly lined up!
Even though over-long lines get truncated rather than pushing everything along. Which could be a bug or a feature depending on use-case. (By using a tput el
, to erase to the end-of-line it looks marginally neater.)