LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
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 08-09-2012, 05:03 AM   #1
niharikaananth
Member
 
Registered: Aug 2011
Posts: 58

Rep: Reputation: Disabled
BASH caculation help


Dear All,
I have a file called "duration" in which time duration is stored in seconds.
Code:
# cat duration 
3162
162
699
12
59
2906
Here is a small script to give the total duration.
Code:
# cat check_usage 
#!/bin/bash
sum=0
while read num; do
	sum=$(($sum + $num)); 
		done < duration
echo $sum seconds usage
echo $(expr $sum / 60) minutes usage
echo $(expr $sum / 60 / 60) hours usage
echo $(expr $sum / 60 / 60 / 24) days usage
If I run this script I am getting the output as below.
Code:
# bash check_usage 
7000 seconds usage
116 minutes usage
1 hours usage
0 days usage
But I would like the output to be as
Code:
7000 seconds usage
116.67 minutes usage
1.94 hours usage
0.08 days usage.
So could anybody please help me in this.

Thanks in advance for your kind help.
 
Old 08-09-2012, 05:14 AM   #2
devUnix
Member
 
Registered: Oct 2010
Posts: 606

Rep: Reputation: 59
bc

Use bc as shown below:

Code:
[demo@localhost Desktop]$ echo "6/2" | bc
3
[demo@localhost Desktop]$ echo "7/2" | bc
3
[demo@localhost Desktop]$ echo "scale=2;7/2" | bc
3.50
[demo@localhost Desktop]$ seconds=65
[demo@localhost Desktop]$ echo "scale=2;$seconds/60" | bc
1.08
[demo@localhost Desktop]$ min=`echo "scale=2;$seconds/60" | bc`; echo "$min Minutes"
1.08 Minutes
[demo@localhost Desktop]$
See the difference?

Bash or Shell Script does not handle floating point values. It can handle only integers. bc is Basic Calculator and in itself is a programming language. Use scale with it as shown above.
 
1 members found this post helpful.
Old 08-09-2012, 08:31 AM   #3
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192
Or you could try using awk which can perform non-integer arithmetic.
 
Old 08-09-2012, 12:49 PM   #4
niharikaananth
Member
 
Registered: Aug 2011
Posts: 58

Original Poster
Rep: Reputation: Disabled
Hi devUnix,
Thank you very much and sorry for the late reply.
Code:
# cat isp1_duration 
124
4526
98615
99269
102450
99998
182450
1057891
782450
I could acheive this as little bit advanced. Thanks for the commands, Since I am not an expert in shell scripting I don't know how to minimize the arrays, but working great!
Code:
# cat check_usage 
#!/bin/bash
sum=0
while read num; do
	sum=$(($sum + $num)); 
		done < isp1_duration

###Print the total usage in seconds### 
echo "                     =================="
echo "                     || ISP1 Details ||"
echo "                     =================="
echo "Total usage in seconds      :           $sum seconds of usage."

###Check if duration is equal/greater than 1 minute###
if [ $sum -ge 60 ]; then
minutes=`echo "scale=2;$sum/60" | bc`
only_minutes=`echo "scale=2;$sum/60" | bc | cut -d. -f 1`
seconds_per_minute=`echo "scale=2;$only_minutes*60" | bc`
remaining_seconds=`echo "scale=2;$sum-$seconds_per_minute" | bc`
echo "Usage in minutes and seconds:        $only_minutes minutes $remaining_seconds seconds of usage."
fi

###Check if duration is equal/greater than 1 hour###
if [ $sum -ge 3600 ]; then
hours=`echo "scale=2;$sum/60/60" | bc`
only_hours=`echo $hours | cut -d. -f 1`
minutes_per_hour=`echo "scale=2;$only_hours*60" | bc`
remaining_minutes=`echo "scale=2;$sum/60-$minutes_per_hour" | bc | cut -d. -f 1`
echo "Usage in hours and minutes  :          $only_hours hours $remaining_minutes minutes of usage."
fi

###Check if duration is equal/greater than 1 day###
if [ $sum -ge 86400 ]; then
days=`echo "scale=2;$sum/60/60/24" | bc`
only_days=`echo $days | cut -d. -f 1`
hours_per_day=`echo "scale=2;$only_days*24" | bc`
remaining_hours=`echo "scale=2;$sum/60/60-$hours_per_day" | bc | cut -d. -f 1`
echo "Usage in days and hours     :          $only_days days $remaining_hours hours of usage."
fi
See the output
Code:
# bash check_usage 
                     ==================
                     || ISP1 Details ||
                     ==================
Total usage in seconds      :           2427773 seconds of usage.
Usage in minutes and seconds:        40462 minutes 53 seconds of usage.
Usage in hours and minutes  :          674 hours 22 minutes of usage.
Usage in days and hours     :          28 days 2 hours of usage.
The above output is very good than that which I had previously expected i.e
Code:
7000 seconds usage
116.67 minutes usage
1.94 hours usage
0.08 days usage
.
Please guide me if anything needs to be modified to minimize the commands/arrays. At last one more thing I would like to print as below only if all conditions(seconds,minutes,hours,days) matches
Code:
Total usage details         :          28 days 2 hours * minutes * seconds of usage.
Once again thanks a ton for your kind guidense.

Last edited by niharikaananth; 08-09-2012 at 12:57 PM.
 
Old 08-09-2012, 01:01 PM   #5
niharikaananth
Member
 
Registered: Aug 2011
Posts: 58

Original Poster
Rep: Reputation: Disabled
Hi grail,
Thanks for the reply.
Quote:
Or you could try using awk which can perform non-integer arithmetic.
How?
May I expect some examples?
 
Old 08-09-2012, 02:28 PM   #6
lithos
Senior Member
 
Registered: Jan 2010
Location: SI : 45.9531, 15.4894
Distribution: CentOS, OpenNA/Trustix, testing desktop openSuse 12.1 /Cinnamon/KDE4.8
Posts: 1,144

Rep: Reputation: 217Reputation: 217Reputation: 217
This works
Code:
#!/bin/bash
sum=2427773
ELAPSEDHRS=$((($sum%86400/3600)))
ELSECNDS=$(($sum%3600))
echo "------ Total seconds: " $sum
echo $(($sum/86400))" days, "$ELAPSEDHRS" hrs, "$((ELSECNDS/60))" minutes, "$((ELSECNDS%60))" seconds"


#===============
# Output:
------ Total seconds:  2427773
28 days, 2 hrs, 22 minutes, 53 seconds
hope it helps.


Ed.: some good time calculation resource is here

Last edited by lithos; 08-09-2012 at 02:31 PM.
 
1 members found this post helpful.
Old 08-09-2012, 09:37 PM   #7
niharikaananth
Member
 
Registered: Aug 2011
Posts: 58

Original Poster
Rep: Reputation: Disabled
Thanks lithos,
Quote:
sum=2427773
ELAPSEDHRS=$((($sum%86400/3600)))
ELSECNDS=$(($sum%3600))
The above arrays is very good instead of my multiple arrays and I am getting the output that what I had really expected!
But still I am unable to calculate and get the correct output using GUI calculator.
So Could you please show me the steps to calculate using GUI calcalator to get the correct output as 2 hours, 22 minutes and 53 seconds for above 2 arrays?
Thanks for your kind help.

Last edited by niharikaananth; 08-09-2012 at 09:38 PM.
 
Old 08-10-2012, 02:50 AM   #8
lithos
Senior Member
 
Registered: Jan 2010
Location: SI : 45.9531, 15.4894
Distribution: CentOS, OpenNA/Trustix, testing desktop openSuse 12.1 /Cinnamon/KDE4.8
Posts: 1,144

Rep: Reputation: 217Reputation: 217Reputation: 217
Quote:
Originally Posted by niharikaananth View Post
Thanks lithos,

The above arrays is very good instead of my multiple arrays and I am getting the output that what I had really expected!
But still I am unable to calculate and get the correct output using GUI calculator.
So Could you please show me the steps to calculate using GUI calcalator to get the correct output as 2 hours, 22 minutes and 53 seconds for above 2 arrays?
Thanks for your kind help.
well, that's called math and is quite simple (once you know it)
It goes like:
Code:
sum=2427773
ELAPSEDHRS=$((($sum%86400/3600)))

expands to:
2427773/86400= 28,099224537037037037037037037037
now "%" (modulo division, prints out the remainder from float number - takes integer part away)
in bash takes the integer 28 away and you get "0,099224537037037037037037037037" 
which you then multiply with 86400 to get the  "8573"
this 8573/3600 gives "2,381388888..." and again it takes only the integer part "2"
which prints out.


ELSECNDS=$(($sum%3600))
this is the same (% = modulo division)
2427773/3600=674,381388888...  - 674 = 0,381388888 * 3600= 1373
then when you are printing out the result:
Code:
echo $(($sum/86400))" days, "$ELAPSEDHRS" hrs, "$((ELSECNDS/60))" minutes, "$((ELSECNDS%60))" seconds"
you are basically "converting" the "1373" to minutes and remaining seconds... just the logic in BASH is needed to understand what "/" and "%" print out in BASH (here is an example and here the operators in bash )
For example:
Code:
$ echo $((2427773/86400)) 
28
the "/" (division operator) prints out only integer part of number

I hope you see it now.

Last edited by lithos; 08-10-2012 at 02:56 AM.
 
Old 08-10-2012, 03:12 AM   #9
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192
Well you will probablky need to tidy it up a bit, but in answer to the default solution requested:
Code:
awk '{sum+=$0}END{printf "seconds: %d\nminutes: %.2f\nhours: %.2f\ndays: %.2f\n",sum,sum/60,sum/60/60,sum/60/60/24}' duration
 
1 members found this post helpful.
Old 08-10-2012, 04:02 AM   #10
niharikaananth
Member
 
Registered: Aug 2011
Posts: 58

Original Poster
Rep: Reputation: Disabled
Dear lithos,
Code:
$ELAPSEDHRS=$((($sum%86400/3600)))
$ echo $ELAPSEDHRS
2
How?
I had really confused and got headache by thinking of it with GUI calculator and at last you could solve the problems by giving good explainations. And also after reading those links I came to know how it is happening.
Code:
$expr 5 % 3
2
how?
It just like below!!!
Code:
3)5(1
  3
------
  2  -->Remainder
------
So the $ELAPSEDHRS are
Code:
$echo $((2427773%86400))
8573
$echo $((8573/3600))
2 hours
.
So the elapsed seconds are
Code:
$echo $((2427773%3600%60))
53 seconds
I understood. Thank you very much for these simple airthmatic tutorials in the bash instead of the multiple arrays that I had made before.
 
Old 08-10-2012, 04:16 AM   #11
niharikaananth
Member
 
Registered: Aug 2011
Posts: 58

Original Poster
Rep: Reputation: Disabled
Hi grail,
Thanks for reply.
Code:
$ awk '{sum+=$0}END{printf "seconds: %d\nminutes: %.2f\nhours: %.2f\ndays: %.2f\n",sum,sum/60,sum/60/60,sum/60/60/24}' duration
seconds: 2427773
minutes: 40462.88
hours: 674.38
days: 28.10
Good, but for human readable format the below is really simple and very good.
Code:
$ bash check_usage
------ Total seconds:  2427773
28 days, 2 hrs, 22 minutes, 53 seconds
Thanks lithos.
Code:
$cat check_usage
#!/bin/bash
sum=0
while read num; do
	sum=$(($sum + $num)); 
		done < duration
ELAPSEDHRS=$((($sum%86400/3600)))
ELSECNDS=$(($sum%3600))
echo "------ Total seconds: " $sum
echo $(($sum/86400))" days, "$ELAPSEDHRS" hrs, "$((ELSECNDS/60))" minutes, "$((ELSECNDS%60))" seconds"
Thans a ton for you all.

Last edited by niharikaananth; 08-10-2012 at 04:20 AM.
 
Old 08-10-2012, 05:03 AM   #12
lithos
Senior Member
 
Registered: Jan 2010
Location: SI : 45.9531, 15.4894
Distribution: CentOS, OpenNA/Trustix, testing desktop openSuse 12.1 /Cinnamon/KDE4.8
Posts: 1,144

Rep: Reputation: 217Reputation: 217Reputation: 217
No problem, I'm glad it helped you solve it.
 
Old 08-10-2012, 08:15 AM   #13
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192Reputation: 3192
Well I did assume that you might do a little of the heavy lifting once I put you on the correct track:
Code:
awk '{sum+=$0}END{hour=60*60;day=24*hour;printf "------ Total seconds: %d\n%d days, %d hrs, %d minutes, %d seconds\n",sum,sum/day,sum%day/hour,sum%day%hour/60,sum%day%hour%60}' duration
 
1 members found this post helpful.
Old 08-14-2012, 12:00 PM   #14
niharikaananth
Member
 
Registered: Aug 2011
Posts: 58

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by grail View Post
Well I did assume that you might do a little of the heavy lifting once I put you on the correct track:
Code:
awk '{sum+=$0}END{hour=60*60;day=24*hour;printf "------ Total seconds: %d\n%d days, %d hrs, %d minutes, %d seconds\n",sum,sum/day,sum%day/hour,sum%day%hour/60,sum%day%hour%60}' duration
Hi Guru,
Super, This is what I had expected

Thanks a ton.
 
  


Reply



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
LXer: Share And Discover Cool Bash Tricks With Bash One-Liners LXer Syndicated Linux News 0 01-30-2012 09:50 AM
Bash problem : -bash: [: /bin/bash: unary operator expected J.A.X Linux - Software 1 09-22-2011 05:52 AM
[SOLVED] Using a long Bash command including single quotes and pipes in a Bash script antcore Linux - General 9 07-22-2009 11:10 AM
BASH -copy stdin to stdout (replace cat) (bash browser) gnashley Programming 4 07-21-2008 01:14 PM
why did bash 2.05b install delete /bin/bash & "/bin/sh -> bash"? johnpipe Linux - Software 2 06-06-2004 06:42 PM

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

All times are GMT -5. The time now is 05:04 PM.

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
Open Source Consulting | Domain Registration