Home > database >  Format currency in Bash
Format currency in Bash

Time:06-29

Is it possible to format currency in Bash?

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

Thanks.

CodePudding user response:

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

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.

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 () {
    local TIMEFORMAT=%U _decsep
    read _decsep < <(eval 'time true' 2>&1)
    _decsep=${_decsep//[0-9]}
    if [[ $1 == -v ]]; then
        local -n _out="$2"
        shift 2
    else
        local _out
    fi
    local _amount=00$(($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.

CodePudding user response:

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).

CodePudding user response:

You can use printf

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

CodePudding user response:

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

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

printf "%'d\n" 19366

Works if the current locale supports the comma monetary 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
  • Related