bash + sed: trim trailing zeroes off a floating point number?
Asked Answered
A

8

8

I'm trying to get trim off trailing decimal zeroes off a floating point number, but no luck so far.

echo "3/2" | bc -l | sed s/0\{1,\}\$//
1.50000000000000000000

I was hoping to get 1.5 but somehow the trailing zeroes are not truncated. If instead of 0\{1,\} I explicitly write 0 or 000000 etc, it chops off the zeroes as entered, but obviously I need it to be dynamic.

What's wrong with 0\{1,\} ?

Akilahakili answered 4/5, 2015 at 15:21 Comment(1)
Presumably this is a test case, otherwise you could change the scale parameter in bc to reduce the number of decimal places.Magnifico
E
16
echo "3/2" | bc -l | sed '/\./ s/\.\{0,1\}0\{1,\}$//'
  • remove trailing 0 IF there is a decimal separator
  • remove the separator if there are only 0 after separator also (assuming there is at least a digit before like BC does)
Epizoon answered 5/5, 2015 at 9:20 Comment(3)
Thanks! Yes, I didn't cover the exception yet to only remove zeroes after separator (I wouldn't want 3500 to be trimmed to 35) or removal of the separator itself if applicable. Wanted to wrap my head around getting the regex to work at all in the first place :) But great addition, thx!Akilahakili
Actually, I don't fully understand the first part of the sed parameter. Being a sed noob, I'm only familiar with sed using s/<searchpattern>/<replacepattern>/. Looking thru man sed, I understand the dot before the s is an 'address', which behaves as an extra filter, i.e. sed /<filter>/s/<search>/<replace>/ will only replace search with replace for input that also matches filter, is that correct?Akilahakili
/\./is a pattern filter on line that contain a dot in it (avoiding to remove trailing 0 on a multiple of 10 like 25000). Filter, activate following action (or group if a {} is used ) only when pattern (or address) of the filter is compliant. So yes, you are correctEpizoon
D
13

Why don't you just set the number of digits you want with scale?

$ echo "scale=1; 3/2" | bc -l 
1.5
$ echo "scale=2; 3/2" | bc -l 
1.50
$ echo "scale=5; 3/2" | bc -l 
1.50000

I recommend you to go through man bc, since it contains many interesting ways to present your result.

Delorsedelos answered 4/5, 2015 at 15:24 Comment(5)
Thanks, I'll look into man bc as it's quite new to me. However in this particular case, I don't want a specific number of digits, but rather maximum precision and just ditch any unnecessary trailing zeroes.Akilahakili
Trailing zeros are necessary for maximum precision. 1.5000 is far more precise than 1.5 (which may be anything between 1.45 and 1.54.Brinkema
it does not reply to question but do the request behind . Let assume that in your reply in case of bc -l is just the sample generator (you still get my vote)Epizoon
@Epizoon yep, I was going to the core of the problem instead of the sed problem the OP found in his workaround. However, to me the best way to control the format is by using printf, like Pedro Lobito's answer shows.Delorsedelos
@Brinkema I agree that in general 1.5000 is different (more precise) than 1.5, but in this particular case I want to get rid of remaining zeroes.Akilahakili
U
6

$ must not be escaped and quote sed pattern:

echo "3/2" | bc -l | sed 's/0\{1,\}$//'
1.5
Unhesitating answered 4/5, 2015 at 15:23 Comment(1)
@Etan actually, the \{1,\} is the more portableMagnifico
N
2

@anubhava has the right reason for your failed command, but just use awk instead:

$ awk 'BEGIN{print 3/2}'
1.5
Nucleoside answered 4/5, 2015 at 21:15 Comment(0)
A
1

You can use printf for that:

printf "%.1f" $(bc -l <<< '3/2')
1.5
Anachronous answered 5/5, 2015 at 6:57 Comment(2)
good one! I thought about using printf but failed to make it work, since I was using printf "%f" $(( 3/2 )) and $(( )) just does int arithmetic.Delorsedelos
That will round every result to 1 decimal place, not strip off trailing zeros as the OP wants.Nucleoside
W
0

One of the handy way to trim off trailing zeroes of a floating number is grep --only-matching option:

$ echo 1 + 0.1340000010202010000012301000000000 | bc -l | grep -o '.*[1-9]'
1.1340000010202010000012301

-o, --only-matching

Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.

Westbound answered 19/9, 2016 at 15:4 Comment(0)
W
0

Here's my take. It removes leading zeros, and then if there is a decimal anywhere in the number, it also removes trailing zeros. This expression also works for numbers preceded or followed by space characters if present.

sed -e "s/^\s*0*//" -e "/\./ s/0*\s*$//"
Wortman answered 14/10, 2019 at 18:18 Comment(0)
H
0

nothing wrong with previous answers, but here's another approach that should work in places where awk/bc/grep/sed aren't available.

all it does is trim the last character if it is a "0" until it is something other than a "0".

decimal="1.50000000000000000000"
echo ${decimal}
while [ "${decimal: -1}" = "0" ]; do
    decimal=${decimal::-1}
done
echo ${decimal}
Hoyt answered 26/9 at 9:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.