Reputation: 678
In bash, how can I modify a float
so that the part coming before the dot is having at least two digits?
I want to make numbers in Column A be displayed as in Column B:
A (Current) B (Desired)
----- ------
8.456 08.456
4.19 04.19
3.5 03.5
I did a lot of searches, but most of what I found talked about how to display numbers with N decimals (e.g. 17.7647 to 17.76
) which was of no help.
Upvotes: 2
Views: 219
Reputation: 84579
You can expand a bit and take the great answer by @anubhava a bit further by allowing the width on both the real-part and fractional-part to be set and fully validating the input and handling any errors in your function. The approach though is the same, using the printf
format string is key.
For example your function can take the floating-point number as the first argument, the width of the real-part as the second, and optionally take the width of the fractional-part as the third, e.g.
#!/bin/bash
formatfloat () {
[ -z "$1" -o -z "$2" ] && { ## validate at least 2 arguments given
printf "error: formatfloat() insufficient arguments.\n" >&2
printf "usage: formatfloat() float width_real [width_fract]\n" >&2
return 1;
}
[[ $1 =~ ^-*[[:digit:]]*[.][[:digit:]]* ]] || { ## validate float
printf "error: formatfloat() not a valid floating point number.\n" >&2
return 1
}
[ "$2" -eq "$2" > /dev/null ] || { ## validate width is an integer
printf "error: formatfloat() width_real not an integer.\n" >&2
return 1
}
local realpart="${1%.*}" ## parameter expansion separates real/fraction parts
local fractpart="${1#*.}"
local width_real="$2"
if [ -n "$3" ]; then ## if fractional part width given
[ "$3" -eq "$3" > /dev/null ] || { ## validate it is an integer
printf "error: formatfloat() width_fract not an integer.\n" >&2
return 1
}
local width_fract="$3" ## output setting both widths
local fppad="$((width_fract - ${#fractpart}))" ## needed fract part rt-pad
[ "$fppad" -le 0 ] && { ## no padding needed
printf "%0*d.%d\n" $width_real $realpart $fractpart
return 0
}
for ((i = 0; i < fppad; i++)); do ## add padding to fract part
fractpart="${fractpart}0"
done
printf "%0*d.%*d\n" $width_real $realpart $width_fract $fractpart
else ## output setting real-part width
printf "%0*d.%d\n" $width_real $realpart $fractpart
fi
return 0
}
A short example with your data could be:
printf "A (Current) B (Desired)\n----- ------\n"
for n in 8.456 4.19 3.5; do
printf "%-14s%s\n" "$n" "$(formatfloat "$n" 2)"
done
Output
$ bash formatfloat.sh
A (Current) B (Desired)
----- ------
8.456 08.456
4.19 04.19
3.5 03.5
Setting Width of Both
for n in 8.456 4.19 3.5; do
printf "%-14s%s\n" "$n" "$(formatfloat "$n" 2 3)"
done
Output
$ bash formatfloat.sh
A (Current) B (Desired)
----- ------
8.456 08.456
4.19 04.190
3.5 03.500
Upvotes: 2
Reputation: 785631
Here is a utility function in bash
to achieve this using printf
:
fpad() {
local n="${1?needs an argument}"
[[ $n == [0-9].* ]] && echo "0$n" || echo "$n"
}
Use it as:
fpad "8.456"
08.456
fpad "4.19"
04.19
fpad "3.5"
03.5
fpad "13.25"
13.25
fpad "1325"
1325
Using Glen's suggestion with read
:
fpad() {
local n="${1?needs an argument}"
local num frac
IFS=. read num frac <<< "$n"
printf '%02d.%d\n' "$num" "$frac"
}
Upvotes: 5
Reputation: 141523
how can I modify a float so that the part coming before the dot is having at least two digits.
There is no utility for that - write your own code for doing that. You would:
I could also see a sed
with two expressions that each one matches with a regex the number of digits before a comma.
Upvotes: 0