As I was writing the Time and date in Unix scripts post last week, I've realized that there's one really useful feature of Unix shell scripting which I haven't covered on my pages here: it's the double bracket parenthesis which allows you to evaluate arithmetic expressions.
Basic arithmetic calculations in Unix scripts
In most scenarios, your script will need only basic arithmetic operations: summing or subtracting numbers, multiplying or dividing them. Using only these operations, you'll be able to implement all sorts of counters and calculate percentages or any other progress indicators you may need.
So far, I've only shown you this way of evaluating arithmetic expressions in Unix shell (yes, it's not a script – you can just type commands one after another right in your shell prompt):
ubuntu$ START=1 ubuntu$ FINISH=5 ubuntu$ ELAPSED=`expr $FINISH - $START` ubuntu$ echo $ELAPSED 4
But an even better way to evaluate arithmetic expressions is to use the built-in functionality of double brackets. Just continue typing in your shell:
ubuntu$ ELAPSED2=$(($FINISH - $START)) ubuntu$ echo $ELAPSED2 4
You see, everything that is inside double brackets gets evaluated and then this calculated value is assigned to the variable. I'm using a different variable – ELAPSED2 – to clearly show that this calculation has nothing to do with the original ELAPSED variable.
If you wonder about the theory behind such a way of evaluating expressions, I should talk a bit about using variables in Unix shells.
As you probably remember, when you're assigning your variable a new value, you're simply specifying the name of the variable to the left of the expression, then use the = sign (it's not just a symbol but an assignment operator by the way), and to the right of this operator goes the expression which represents the new value:
Variable substitution operator
As you also remember, when you want to access the value of the variable, for example to print it out, you use the variable name with a leading $ sign. That's because $, once again, isn't just a fancy symbol, but in fact a special character in Bash – it's a variable substitution operator, which means your Unix script substitutes the variable name you're specifying in the script with the value of the variable:
ubuntu$ echo $MYVAR 3
Using the substitution operator ($) before the name of a variable is crucial. If you omit the $ sign, your shell will think you have simply passed it a text string, and will not recognize it to be a name of the variable:
ubuntu$ echo MYVAR MYVAR
Expression evaluation explained
Coming back to arithmetic evaluations, you can probably see now that a line similar to this:
ubuntu$ ELAPSED=$(($FINISH - $START))
uses the variable substitution operator ($) and it's therefore only logical that the further specified expression gets evaluated and the ELAPSED variable gets assigned with the resulting value.
Once again, using $ sign is crucial as without it your shell will not understand you:
ubuntu$ ELAPSED=(($FINISH - $START)) sh: syntax error near unexpected token `('
So, what do you think? I hope this makes sense to you, and will be sure to use this technique from now on – once you get used to it, it's really easy to write and read shell scripts based on this functionality.
Let me know if there's anything else you'd like to hear an explanation of! I'll do my best! 🙂
Thanks for the information!
Nails Carmody says
An equivalent way of perform this statement:
ELAPSED=$(($FINISH – $START))
with bash/ksh is using the let keyword:
let ELAPSED="FINISH – START"
It's a personal choice, but most shell programmers tend to use the method you intially introduced.
You can also set expression entirely withn parenthesis and elimiante some $
((ELAPSED=FINISH – START))
Again, it's personal preference
Finally, in shell programming, it's typical to have to increase/decrease a counter – say by 1. this works:
echo $cnt # should equal 1
alternatively, similar to "C" you could do this:
Just thought you'd like to know.
Thanks a lot. GOd Bless you.
Gleb Reys says
Glad to have helped, Chima!
Bruce Chase says
what would the expression look like if you wanted to add a long list of number?
Gleb Reys says
Hi Bruce, I hope the above like (comment #7) answers your question.
Thanks a lot !! that was really very helpful 🙂
I tried the double bracket assignments but it doesn't work. On my machine it will complain :
test: =: unary operator expected
for the line:
test = $(( $i – $j))
Still don't know what is wrong. But thanks for the explanation!
i dint understand