Addition in bash

Ray Parrish crp at cmc.net
Wed Oct 14 13:21:55 UTC 2009


David N. Lombard wrote:
> Ray Parrish wrote:
>   
>> Hello,
>>
>> I have the following script fragment
>>
>> Seconds=0;
>> while [ "$Seconds" -lt "60" ]
>>   do
>>   sleep 5;
>>   Seconds=$Seconds+5;
>>   padsp espeak "$Seconds"
>> done
>>
>> For some reason Seconds becomes "0+5" instead of the integer value 5 
>> which is what I am attempting to get it to be.
>>     
>
> Yes, you're doing a string concatenation there, "+5" is being 
> concatenated to "0" to get "0+5". Exactly what you asked for. ;)
>
>   
>> Does anyone know how to do integer math in bash?
>>     
>
> For *bash* and not sh, I would rewrite the above as:
>
>    Seconds=5
>    while [[ $Seconds < 60 ]]
>    do
>      sleep 5
>      (( Seconds += 5 ))
>      padsp espeak $Seconds
>    done
>
> Note these changes:
>
> 1) I used the *bash* double bracket conditional form.  This offers 
> better testing *and* it changes how the strings are interpreted, for 
> example, you don't have to quote null strings or protect special 
> characters since you're not building an executable string.
>
> 2) The double parentheses arithmetic expression.  This doesn't require 
> the $ to indicate a variable and permits C-style operators.
>
> 3) You don't have to quote every occurrence of every string.  You only 
> need to be mindful of spaces and special characters.  So, I didn't quote 
> the $Seconds on the padsp line.
>
> 4) You only need the semicolon to break a single physical line into 
> multiple statements.  You don't have that here.  An example that would 
> require the semicolon is
>
>    while [[ $Seconds < 60 ]] ; do
>
> BTW, you may have meant to initialize $Seconds at 0.  The current form 
> will result in 10, 15, 20, 25, ... 60.
>
> Also, you could do this without arithmetic using
>
>    for Seconds in $(seq 5 5 60) ; do
>      sleep $Seconds
>      padsp espeak $Seconds
>    done
>
> Note that seq puts the increment before the last value, unlike most for 
> constructs.
>
> If you really did want sh, Bourne shell, you would do the arithmetic as
>
>    Seconds=`expr $Seconds + 5
>   
Thank you for all of the clarifications! I learned a lot from your post, 
and have implemented many changes into the script already. I was 
surprised to learn that the semi-colon isn't needed after every line, as 
that is what was stated was required in a bash tutorial I read once.

Here is the latest version of the script, which is working quite nicely, 
except in timer mode with intervals that do not divide evenly into 60 
seconds, it ends after the duration has expired. I've already got an 
idea how to take care of that.

#!/usr/bin/env bash
# Usage: /folderpath/Timer.sh n n
# Where n and n are numeric values expressed in seconds. The first n is 
the interval in seconds of how often you would like to see updates to the
# timer display.
# The second n is the duration in seconds you would like the timer to 
run before shutting off. This is for use as an event timer.
# Replace folderpath with the actual path of folder names leading to the 
scripts location.
# To stop the script at any point press a character key in Terminal. By 
doing this you can use the Timer script as a stop watch, just set a long
# enough duration to cover at least the event length you are attempting 
to time, and hit any letter, number, or punctuation key to stop timing
# when the event is over.
declare -i Minutes=0
declare -i Seconds=0
declare -i Elapsed=0
Duration=$2
Interval=$1
# if Interval is blank (unspecified)
if [ "$Interval" == "" ]
    then
            Interval=1 # set default interval of one second is set
fi
clear
echo "Elapsed Time: $Minutes Minutes $Seconds Seconds"
echo "$Interval Interval" # echo interval setting
# read timeout for any key of one second forces us to trim 1 second from 
the Interval for proper execution.
(( Interval -=1 ))
# if Duration is blank (unspecified)
if [[ "$Duration" == "" ]]
    then
           Duration=300 # set default interval of 300 seconds.
fi
echo "$Duration Duration" # echo Duration setting
echo "To exit timer press any letter, number, or punctuation key."
echo "Timer will then exit after the next interval expires."
# While elapsed time is less than the Duration setting do loop till done.
while [[ $Elapsed -lt $Duration ]]
  do
# first sleep for the interval
if [[ $Interval -ne 0 ]]
   then
           sleep "$Interval"
fi
# Increment Seconds and Elapsed by the Interval setting
  Seconds=$(( $Seconds +$Interval +1 ))
  Elapsed=$(( $Elapsed +$Interval + 1))
# if Seconds equals 60 or is greater than 60 seconds
  if [ $Seconds == 60 ] || [ $Seconds -gt 60 ]
      then
              Seconds=$(( $Seconds - 60)) # trim 60 seconds off the 
reading and
              Minutes=$(( $Minutes + 1)) # add one to the Minutes value
  fi
# clear the screen between each timer update
clear
# Update the timer display to the current value
if [ $Minutes == 1 ]
   then
           echo "Elapsed Time: $Minutes Minute $Seconds Seconds"
           echo "$(( $Interval +1 )) Second Interval" # echo interval 
setting
           echo "$Duration Seconds Duration" # echo Duration setting
           echo "To exit timer press any letter, number, or punctuation 
key."
           echo "Timer will then exit after the next interval expires."
   else
           echo "Elapsed Time: $Minutes Minutes $Seconds Seconds"
           echo "$(( $Interval +1 )) Second Interval" # echo interval 
setting
           echo "$Duration Seconds Duration" # echo Duration setting
           echo "To exit timer press any letter, number, or punctuation 
key."
           echo "Timer will then exit after the next interval expires."
fi
read -t 1 -n 1 ExitFlag
if [ "$ExitFlag" != "" ]
    then
            exit
fi
done
exit

Later, Ray Parrish


-- 
The Future of Technology.
http://www.rayslinks.com/The%20Future%20of%20Technology.html
Ray's Links, a variety of links to usefull things, and articles by Ray.
http://www.rayslinks.com
Writings of "The" Schizophrenic, what it's like to be a schizo, and other
things, including my poetry.
http://www.writingsoftheschizophrenic.com






More information about the ubuntu-users mailing list