Commifying Numbers
Problem
You’d like to add a thousands-place separator to long numbers.
Solution
Depending on your system and configuration, you may be able to use printf’s ' format flag with a suitable local. Thanks to Chet Ramey for this solution, which is by far the easiest if it works:
$ LC_NUMERIC=en_US.UTF-8 printf "%'d\n" 123456789 123,456,789 $ LC_NUMERIC=en_US.UTF-8 printf "%'f\n" 123456789.987 123,456,789.987000
Thanks to Michael Wang for contributing the following shell-only implementation and relevant discussion:
# cookbook filename: func_commify function commify { typeset text=${1} typeset bdot=${text%%.*} typeset adot=${text#${bdot}} typeset i commified (( i = ${#bdot} - 1 )) while (( i>=3 )) && [[ ${bdot:i-3:1} == [0-9] ]]; do commified=",${bdot:i-2:3}${commified}" (( i -= 3 )) done echo "${bdot:0:i+1}${commified}${adot}" }
Or you can try one of the sed solutions from the sed FAQ, for example:
sed ':a;s/\B[0-9]\{3\}\>/,&/;ta' /path/to/file # GNU sed sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' /path/to/file # other seds
Discussion
The shell function is written to follow the same logical process as a person using a pencil and paper. First you examine the string and find the decimal point, if any. You ignore everything after the dot, and work on the string before the dot.
The shell function saves the string before the dot in $bdot
, and after the dot (including the dot)
in $adot
. If there is no dot, then
everything is in $bdot
, and $adot
is empty. Next a person would ...
Get bash Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.