1

Is it possible to format currency in Bash?

Example data is received as 19366 Data to be displayed as $193,66

Thanks.

2
  • printf "%.2f \n" $((19366/100)) works fine. Commented Jun 29, 2022 at 2:20
  • Actually this does not work as it is rounding off. Commented Jun 29, 2022 at 2:25

6 Answers 6

4

Simply handle your value as a text string, instead of a number, and insert a dollar sign and a comma at the correct positions:

$ v=19366 $ printf '$%s,%s\n' "${v:0: -2}" "${v: -2}" $193,66 

${v:offset:length) expands as the substring of $v that starts at character offset (counting from 0) and which length is length. But negative offsets and lengths can be used to refer to the end of the string.

${v:0:-2} expands as the substring of $v that starts at the beginning (0) and which length is the number of remaining characters minus two (-2). In our example this is 193.

${v: -2} expands as the substring of $v that starts two characters before the end (-2) and which length (not specified) is the number of remaining characters. In our example this is 66. Note the space between : and -2, it is needed to avoid another interpretation by the shell (providing default value 2 if v is unset or null).

Sign up to request clarification or add additional context in comments.

5 Comments

Have a look at bottom of my answer, there is a coma! $12.345,67
Yes, fine. I wasn't suggesting that your answer is incorrect. I simply remark that the OP want a comma, nothing else. So there is no need for complicated things involving the locale. Just insert a comma in the right place and voilà.
Hardcoding decimal separator is not portable! Using locale is a recommendable good practice.
OK, forget it, it's not very important.
( I disagree: Trying to use good practice by habit, is important! ;-)
3

Preamble In your request, you use coma , as decimal separator (radix mark). For locale support, see second part of my answer.

1. Pseudo floating poing using integer as strings

I often use this kind of pseudo float:

amount=123456 amount=00$amount # avoid bad length error printf '$%.2f\n' ${amount::-2}.${amount: -2} 
$1234.56 
for amount in 0 1 12 123 1234 12345;do amount=00$amount printf '$%.2f\n' ${amount::-2}.${amount: -2} done 
$0.00 $0.01 $0.12 $1.23 $12.34 $123.45 

As a function:

int2amount() { if [[ $1 == -v ]]; then local -n _out="$2" shift 2 else local _out fi local _amount=00$(($1)) printf -v _out $'$%\47.2f' ${_amount::-2}.${_amount: -2} [[ ${_out@A} != _out=* ]] || echo "$_out" } 

Then

int2amount 123456 
$1’234.56 
int2amount -v var 1234567 echo $var 
$12’345.67 

2. Remark regarding locale, decimal separator and thousand separators

In your request, your radix mark is a coma ,. This depend on your locale configuration. U could hit something like:

set | grep ^LC\\\|^LANG 

to show how this is configured on your host.

As there are many issues regarding locales, I've asked How to determine which character is used as decimal separator or thousand separator under current locale as separated question.

Try:

for locvar in C en_US.UTF-8 de_DE.UTF-8 ;do LC_NUMERIC=$locvar int2amount 1234567 done 
$12345.67 $12,345.67 bash: line 1: printf: 0012345.67: invalid octal number $12.345,00 

Error because unsing de_DE locale configuration, you have to use a coma as separator (Decimal separator at wikipedia).

This is already know to produce issues using bc: How do I change the decimal separator in the printf command in bash?

Final function unsing variable decimal separator

int2amount () { if [[ $1 == -v ]]; then local -n _out="$2" shift 2 else local _out fi local _amount=00$(($1)) _decsep printf -v _decsep %.1f 1 _decsep=${_decsep:1:1} printf -v _out '$%'\''.2f' ${_amount::-2}${_decsep}${_amount: -2} [[ ${_out@A} != _out=* ]] || echo "$_out" } 
for locvar in C en_US.UTF-8 de_DE.UTF-8 ;do LC_NUMERIC=$locvar int2amount 1234567 done 
$12345.67 $12,345.67 $12.345,67 

Note about LC_ALL: If in your environment, a variable $LC_ALL is defined, all demos using LC_NUMERIC won't work because LC_ALL is over. You have to unset LC_ALL or use:

LC_ALL=$locvar LC_NUMERIC=$locvar int2amount 1234567 

in last demo.

Comments

1

You can use printf

amount="240570.578" printf "%'.2f\n" $amount > 240,570.58 

1 Comment

This does not work for my example. This is the output 19,366.00
0

printf does have a thousands grouping format specifier flag, however the character used to denote the groups (non-monetary grouping character) depends on locale (LC_NUMERIC).

The C or POSIX locale uses no grouping character. Therefore you can't do this portably with printf.

printf "%'d\n" 19366 

Works if the current locale supports the comma grouping character.

In my bashrc, I use the following function to add thousands groupings to any integer, using comma (,) and preserving a non numeric prefix (like $, or - for negative numbers). It doesn't depend on locale, but does require rev.

commafy () { printf %s "${1%%[0-9]*}" printf '%s\n' "${1##*[!0-9]}" | rev | sed -E 's/[0-9]{3}/&,/g; s/,$//' | rev } 

Example:

commafy '$19366' # gives $19,366 

You could slightly simplify this too:

printf %s \$ printf '%s\n' 19366 | rev | sed -E 's/[0-9]{3}/&,/g; s/,$//' | rev 

Comments

0

Simplistically -

$: sed -E 's/([0-9]*)([0-9][0-9])$/$\1,\2/'<<<"19366" $193,66 

Comments

0

The question actually mixes two different problems:

  1. Converting cents to US-Dollar (or Euros, or whatever currency)
  2. Using the correct currency format (currency_symbol, mon_decimal_point, mon_thousands_sep, ...)

The first can be solved by using either external tools like bc or a shell that supports floating point operations like ksh. Bash only supports integer arithmetic.

The latter can be solved by using locale information. See here for an example.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.