LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 10-17-2012, 12:11 AM   #1
sylye
Member
 
Registered: Feb 2003
Location: Malaysia
Distribution: Mandrake 9.1, Debian 3.1,Centos 5.x,6.x,Slackware 13.37,14.0,14.1
Posts: 48

Rep: Reputation: 0
Preferred way to do arithmetic in bash ?


Hi,

Which way is the preferred way you use in doing arithmetic in bash, among expr, $(()) and let ?

I need to do a series of arithmetic with the number with zero padding, like 006767.

I use $(()) and let, they doesn't seem to recognize well the zero padding number. However expr do a good job here. Here is the output:
Code:
[11:48:43 sylye@pc0043 ~]$ echo `expr 006767 + 9 `
6776
[12:04:46 sylye@pc0043 ~]$ let "NEWNO = 0067 + 9"; echo $NEWNO
64
[12:37:05 sylye@pc0043 ~]$ echo $((006767 + 9))
3584
[12:37:26 sylye@pc0043 ~]$
It seems like expr is the better way to do all the arithmetic. Am I right to assume this ?
 
Old 10-17-2012, 12:35 AM   #2
shivaa
Senior Member
 
Registered: Jul 2012
Location: Grenoble, Fr.
Distribution: Sun Solaris, RHEL, Ubuntu, Debian 6.0
Posts: 1,800
Blog Entries: 4

Rep: Reputation: 286Reputation: 286Reputation: 286
Alternatively, you can use awk program for calculations, as follow:
echo | awk '{ print <arithmatic operation> }'
For instance:
echo | awk '{ print 100-100*5/10 }' would result in:
50
 
Old 10-17-2012, 12:44 AM   #3
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.9, Centos 7.3
Posts: 17,374

Rep: Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383
Leading zeros can be tricky; some tools assume this means an octal num.

As per your experiments, 'expr' ignores leading zeroes, 'let' assumes octal; not sure why (()) comes up with that answer... probably something similar.
The technical downside of expr is that its a separate tool, therefore another process being invoked, so a bit more overhead on your system.

Another tool is bc http://linux.die.net/man/1/bc
Code:
echo "0067 + 9"|bc
76
 
1 members found this post helpful.
Old 10-17-2012, 01:40 AM   #4
A.Thyssen
Member
 
Registered: May 2006
Location: Brisbane, Australia
Distribution: linux
Posts: 153

Rep: Reputation: 44
Really it depends on what you are doing and what you can assume is on the system.

older bash's or scripts that may run under bourne shell can not use $(()).

expr and $(()) is limited to integers only.

awk can do math using floats and is not very big by todays standards, and can handle columns of data (text tables)

perl has access to basically the full math library and can process any sort of data, or even network connections and full databases. It also has even better data storage

bc on the otherhand can handle ANY sized number or any scale (number of decimal places) I have used it with numbers that has over a thousand digits.

Really it is just what your needs and what limitations you have.


Actually there are other solutions too. I have image processing scripts using ImageMagick. As I have to have the "convert" command on the system for the script to work, I often use that as I can't be as equally sure bc, awk, or perl, is available for math processing (such as under cgiwin). Its a odd way of doing it but it removes added script dependancies.
 
1 members found this post helpful.
Old 10-17-2012, 01:40 AM   #5
sylye
Member
 
Registered: Feb 2003
Location: Malaysia
Distribution: Mandrake 9.1, Debian 3.1,Centos 5.x,6.x,Slackware 13.37,14.0,14.1
Posts: 48

Original Poster
Rep: Reputation: 0
Quote:
Leading zeros can be tricky; some tools assume this means an octal num.
chrism01,

You're correct. It seems both let and $(()) think '006767' is octal, which equal to 3575 in decimal, and 0067 as 55. I mistakenly made a typo in my experiment above, so the correct one should be:

Code:
[14:24:49 sylye@pc0043 ~]$ let "NEWNO = 006767 + 9"; echo $NEWNO
3584
[14:24:54 sylye@pc0043 ~]$ echo $((006767 +9))
3584
[14:24:56 sylye@pc0043 ~]$ let "NEWNO = 0067 + 9"; echo $NEWNO
64
[14:25:04 sylye@pc0043 ~]$ echo $((0067 +9))
64
[14:25:09 sylye@pc0043 ~]$
So the earlier $(()) gave a correct answer.

However, if we are to use let and $(()), how to make them think '006767' as decimal ?
 
Old 10-17-2012, 03:37 AM   #6
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.9, Centos 7.3
Posts: 17,374

Rep: Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383
An interesting qn, here's a few things I found on the net

Code:
tlq=$(echo $t | sed 's/0*//')
echo $t
0067
echo $tlq
67

Code:
printf "%d\n" 00005
5
http://blog.famzah.net/2010/08/07/be...ric-variables/

I've got a feeling you should be able to use bash param fn http://tldp.org/LDP/abs/html/paramet...stitution.html, but I can't find a general soln ie any num of leading zeros, so far...
I'm sure someone else will
 
Old 10-17-2012, 03:53 AM   #7
sylye
Member
 
Registered: Feb 2003
Location: Malaysia
Distribution: Mandrake 9.1, Debian 3.1,Centos 5.x,6.x,Slackware 13.37,14.0,14.1
Posts: 48

Original Poster
Rep: Reputation: 0
hi chrism01,

I found the answer in another place and as well as in the link you have posted

Just put 'base#your_number' to tell the bash what base we are actually using, then let and $(()) will know how to do their job:

Code:
[16:43:22 sylye@pc0043 ~]$ echo $(( 10#006767 + 9 ))
6776
[16:43:23 sylye@pc0043 ~]$ echo $((16#006767 + 9))
26480
[16:43:41 sylye@pc0043 ~]$ echo $((8#006767 + 9))
3584
[16:43:47 sylye@pc0043 ~]$  let "NEWNO=10#006767+9"; echo $NEWNO
6776
[16:44:15 sylye@pc0043 ~]$  let "NEWNO=8#006767+9"; echo $NEWNO
3584
[16:44:19 sylye@pc0043 ~]$  let "NEWNO=16#006767+9"; echo $NEWNO
26480
Just found this explained in ABS guide also http://tldp.org/LDP/abs/html/numerical-constants.html

shell script is really so cool !

Thanks for A.Thyssen as well for the ideas
 
Old 10-17-2012, 04:36 AM   #8
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.9, Centos 7.3
Posts: 17,374

Rep: Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383Reputation: 2383
Yeah, but I was thinking a bash param trick was possible and would be more elegant

Actually, Manfred Schwarb's soln there is pretty slick, inc a fail safe for a value that only contains zero.
 
Old 10-17-2012, 08:25 PM   #9
A.Thyssen
Member
 
Registered: May 2006
Location: Brisbane, Australia
Distribution: linux
Posts: 153

Rep: Reputation: 44
Quote:
Originally Posted by chrism01 View Post
An interesting qn, here's a few things I found on the net

Code:
tlq=$(echo $t | sed 's/0*//')
echo $t
0067
echo $tlq
67
The above will fail for a number like 8001

The sed should be sed 's/^00*//'
the extra zero is not really needed but it is more exact.
 
Old 10-17-2012, 10:45 PM   #10
shivaa
Senior Member
 
Registered: Jul 2012
Location: Grenoble, Fr.
Distribution: Sun Solaris, RHEL, Ubuntu, Debian 6.0
Posts: 1,800
Blog Entries: 4

Rep: Reputation: 286Reputation: 286Reputation: 286
Quote:
Originally Posted by sylye View Post
hi chrism01,

I found the answer in another place and as well as in the link you have posted

Just put 'base#your_number' to tell the bash what base we are actually using, then let and $(()) will know how to do their job:

Code:
[16:43:22 sylye@pc0043 ~]$ echo $(( 10#006767 + 9 ))
6776
[16:43:23 sylye@pc0043 ~]$ echo $((16#006767 + 9))
26480
[16:43:41 sylye@pc0043 ~]$ echo $((8#006767 + 9))
3584
[16:43:47 sylye@pc0043 ~]$  let "NEWNO=10#006767+9"; echo $NEWNO
6776
[16:44:15 sylye@pc0043 ~]$  let "NEWNO=8#006767+9"; echo $NEWNO
3584
[16:44:19 sylye@pc0043 ~]$  let "NEWNO=16#006767+9"; echo $NEWNO
26480
Just found this explained in ABS guide also http://tldp.org/LDP/abs/html/numerical-constants.html

shell script is really so cool !

Thanks for A.Thyssen as well for the ideas
Can these commands ie. let and then echo, print floating poiint numbers... NO!! It will convert the resulting number in integer and print it. So I think this is not a preferred way to work with. Instead you can use awk code to print full floating point result.
 
Old 10-17-2012, 11:25 PM   #11
shivaa
Senior Member
 
Registered: Jul 2012
Location: Grenoble, Fr.
Distribution: Sun Solaris, RHEL, Ubuntu, Debian 6.0
Posts: 1,800
Blog Entries: 4

Rep: Reputation: 286Reputation: 286Reputation: 286
I have got one solution and it's working perfectly in all environments, and gives result in desired format:

#!/bin/bash
var1=1111688
var2=374335
echo | awk "BEGIN{print 100 - $var2*100/$var1}"
Output: 66.3273


For more details please go though: http://www.linuxquestions.org/questi...wk-4175432706/

Last edited by shivaa; 10-17-2012 at 11:30 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] arithmetic in bash xeon123 Linux - Newbie 9 04-23-2011 09:39 AM
bash, for loop, and arithmetic rmount Programming 13 05-23-2007 01:27 AM
Bash arithmetic Blackout_08 Programming 2 06-08-2006 10:37 PM
simple arithmetic in bash gfrair Linux - Newbie 9 03-16-2005 02:09 PM
Bash, non-integers and arithmetic causticmtl Programming 5 07-16-2003 09:15 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 04:58 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration