LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-31-2010, 09:27 AM   #1
gimpy530
Member
 
Registered: Oct 2007
Posts: 98

Rep: Reputation: 16
Arithmetic in Bash (Value too great for base)


So I am trying to add logic to a script so that it will calculate its runtime on its own. I found some code for Korn Shell which should do the job, but sometimes when I run it in Bash it gives me an error:

Code:
line 33: ((: BTIME=(10*3600)+(08: value too great for base (error token is "08")
The relevant portion of the code is:

Code:
((BTIME=($(date +%H)*3600)+($(date +%M)*60)+$(date +%S)))
1. Is there any problems with that code above in Bash since it was written for Korn?

I know the issue has to do with there being a leading 0 so Bash thinks it is an octal number, but too high to be an octal so it prints an error.

2. So how do I force Bash into knowing that the result is decimal?

In post #6 in the from link below, they said you can specify a base number with base#number, but I'm not sure how to do that with this code as it is more complicated that the example given. I'm new to arithmetic in Bash, new as in never even thought about it before let alone done anything with it.

Original code: http://slashhome.wordpress.com/2008/...e-calculation/

Post about a similar issue: http://ubuntuforums.org/showthread.php?p=4206419
 
Old 01-31-2010, 11:01 AM   #2
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
the problem is that "06" will be interpreted by bash as a octal number because it starts with a zero ('0').

For 01 up to 07 this is not a problem, but "08" and "09" are invalid in octal.
In your script this can happen for hours, minutes as well as seconds.

Either convert the digit-strings containing the hours, minutes and seconds to valid decimal integers (i.e. strip leading zeroes) or use a different way to calculate the number of seconds since midnight.

Last edited by Hko; 01-31-2010 at 11:05 AM.
 
Old 01-31-2010, 02:11 PM   #3
H_TeXMeX_H
LQ Guru
 
Registered: Oct 2005
Location: $RANDOM
Distribution: slackware64
Posts: 12,928
Blog Entries: 2

Rep: Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301Reputation: 1301
That syntax will only work with ksh, instead try:

Code:
echo "($(date +%H)*3600)+($(date +%M)*60)+$(date +%S)" | bc
 
Old 01-31-2010, 03:25 PM   #4
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
Or simply don't let date pad fields with zeros:
Code:
BTIME=$(($(date +%_H)*3600+$(date +%_M)*60+$(date +%_S)))
 
Old 01-31-2010, 04:24 PM   #5
gimpy530
Member
 
Registered: Oct 2007
Posts: 98

Original Poster
Rep: Reputation: 16
@colucix

That line worked perfectly. I'll try to change the ETIME one myself.

Thanks everyone.
 
Old 01-31-2010, 07:49 PM   #6
gimpy530
Member
 
Registered: Oct 2007
Posts: 98

Original Poster
Rep: Reputation: 16
One more problem. The beginning of the script created BTIME and of course near the end ETIME is created. Just before ETIME is created there is a section which checks if it is the same day. If it is not it adds 1 days worth of seconds to the counter. This part is causing problems.

Code:
BDAY=$(date +%_e)
BTIME=$(($(date +%_H)*3600+$(date +%_M)*60+$(date +%_S)))

#Other code here

EDAY=$(date +%_e)

if [ $BDAY = $EDAY ]; then # This assumes run time is not over 48 hours.
DAY=0
else
DAY=86400
fi

ETIME=$(($DAY+$(date +_%H)*3600+$(date +%_M)*60+$(date +%_S))) #Here is the problem

echo "Day is $DAY"
echo "BTIME is: $BTIME"
echo "ETIME is: $ETIME"
SECONDS=$(($ETIME - $BTIME))
echo "SECONDS: $SECONDS"
HOURS=$(($SECONDS / 3600))
echo "HOURS: $HOURS"
MINUTES=$(($SECONDS / 60)) #Not finished
echo "MINUTES: $MINUTES"
In the current run of the the script $DAY=0. When it tries to add $DAY to $ETIME, it gives the following results:

Code:
Day is 0
BTIME is: 70031
ETIME is: 1633
SECONDS: -68398
HOURS: -18
MINUTES: -1139
Why does it mess up when adding a variable which is 0?
 
Old 02-01-2010, 03:22 AM   #7
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
Code:
ETIME=$(($DAY+$(date +_%H)*3600+$(date +%_M)*60+$(date +%_S)))
A little bug here. You have to invert the chars highlighted in red. Moreover note that the date format %_e is not needed, since %e is already padded with spaces (not an error, anyway).

An aside note: if I understand right, you want to check the execution time of your code. Why not simply compute the date in seconds since epoch (%s) before and after the block of code and check the difference? If you have simply to compute a difference you don't really need to set a reference time (midnight of the current day) and let date use its own reference (epoch). For example:
Code:
#!/bin/bash
BTIME=$(date -u +%s)
<code here>
ETIME=$(date -u +%s)
SECONDS=$((ETIME - BTIME))
echo $SECONDS
Note that -u for UTC time is needed to avoid confusion if you run the script during the passage from/to Daylight Saving Time.

Edit: I forgot to mention that SECONDS is not a good choice for a variable name, since $SECONDS is a bash built-in variable which returns the number of seconds since shell invocation (see man bash for details). This means that SECONDS is constantly updated and its value changes automatically during the execution of the script. Indeed, this could be the solution to your quest: just check the value of SECONDS after the block of code and the trick is done. I don't know about portability of this feature, anyway.

A last note: if you want to compute the execution time in hours, minutes and seconds, again you can let the date command do the job. For example:
Code:
date -ud @$SECONDS +"Execution time: %H:%M:%S"
Don't forget the -u option. Hope this helps!

Last edited by colucix; 02-01-2010 at 03:42 AM.
 
Old 02-01-2010, 01:22 PM   #8
gimpy530
Member
 
Registered: Oct 2007
Posts: 98

Original Poster
Rep: Reputation: 16
Here it is:

Code:
DATE='date +%m-%d-%y' #Change format here
TIME='date +%r' #Change format here
EMAIL='someone@gmail.com' #E-mail used for notifications if enabled.

STARTDATE=$($DATE) #Used for logging
STARTTIME=$($TIME) #Used for logging
BTIME=$(date -u +%s) #Used for time calculation

#Other code here

ENDDATE=$($DATE) #Used for logging
ENDTIME=$($TIME) #Used for logging
ETIME=$(date -u +%s) #Used for time calculation
DURSEC=$((ETIME - BTIME))
DURDAYS=$(($DURSEC / 86400))
DURHOURS=$(( ($DURSEC - ($DURDAYS * 86400)) / 3600))
DURMIN=$(( (($DURSEC - ($DURDAYS * 86400)) - ($DURHOURS * 3600)) / 60))
REMSEC=$(( (($DURSEC - ($DURDAYS * 86400)) - ($DURHOURS * 3600)) - ($DURMIN * 60) ))

(echo "Server: $HOSTNAME"
echo "Script: ${0##*/}"
echo "Script Location: $(dirname $0)"
echo "Out Log: $OUTLOG"
echo "Error Log: $ERRLOG"
echo "Backup sources are: ${BKUPSRC[*]}"
echo "Start: $STARTDATE - $STARTTIME"
echo "End: $ENDDATE - $ENDTIME"
echo "Duration: $DURDAYS Days, $DURHOURS hours, $DURMIN minutes, $REMSEC seconds")|mail -s \
"Completed run of script ${0##*/} on $HOSTNAME" $EMAIL
Still wonder why adding a variable that was 0 caused it to have problems.

Last edited by gimpy530; 02-01-2010 at 01:25 PM.
 
Old 02-01-2010, 04:05 PM   #9
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
Quote:
Originally Posted by gimpy530 View Post
Still wonder why adding a variable that was 0 caused it to have problems.
The problem was not the addition of 0, but the little bug I mentioned in my previous post. Suppose the ETIME was computed at 22:54:20. The result of the bugged version was:
Code:
ETIME = $((0 + _22*3600 + 54*60 + 20))
           0 +        0 +  3240 + 20  = 3260
This is due to the fact that unassigned variables can be used inside the arithmetic operator and the resulting (buggy) _22 is indeed interpreted as a variable name, whose value is 0.
 
  


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
bash, for loop, and arithmetic rmount Programming 13 05-23-2007 01:27 AM
BASH, simple arithmetic helptonewbie Programming 9 01-10-2007 05:53 PM
Bash arithmetic Blackout_08 Programming 2 06-08-2006 10:37 PM
[Bash] 09: value too great for base (error token is "09") Erhnam Programming 3 02-25-2005 04:25 AM
Bash, non-integers and arithmetic causticmtl Programming 5 07-16-2003 09:15 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:16 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
Open Source Consulting | Domain Registration