Numbers and Arithmetic Expansion
backup.sh should keep archives for 30 days and report that as weeks. You write weeks=$keep_days/7, echo it, and Bash proudly prints 30/7. Since every value is text, Bash needs a signal before it will do maths.
The rule
Maths lives inside
$(( )), and Bash counts only whole numbers.
$(( expression )) evaluates the expression and puts the result in its place. Inside the double parentheses you can drop the $ from variable names and use spaces freely:
keep_days=30
weeks=$(( keep_days / 7 )) # 4
spare=$(( keep_days % 7 )) # 2
echo "Keeping $weeks weeks and $spare days"The operators are the familiar ones: + - * /, % for remainder, ** for power. Division throws away the remainder: 7 / 2 is 3.
Close relatives:
(( ... ))without the$runs arithmetic for its effect, such as(( count++ ))or(( total += size )). Its exit status is success when the result is non-zero, which makes it handy inif.let count=count+1is an older spelling of the same idea.expr 7 + 2is an old external program; you will see it in old scripts, but$(( ))is faster and clearer.
For decimals, hand the sum to a calculator program such as bc:
echo "scale=2; 30 / 7" | bc # 4.28The shortcut
Look for the double parentheses. Outside them, +, * and / are just characters in a string. Inside them, they are maths on whole numbers. So for any expression, ask two questions: is it inside (( ))? and is there a division that could leave a remainder?
Inside the parentheses?
Yes, so this is arithmetic, and
keep_daysneeds no dollar sign.
A second trap: a leading zero makes Bash read a number as octal, so $(( 08 + 1 )) is an error. This bites when you do maths on dates like 08; strip the zero first.
Drills
Answer fast — trust the rule.
What does echo $(( 17 / 5 )) print?
What does echo $(( 17 % 5 )) print?
After a=2, what does echo "$a*3" print?
What does n=5; (( n += 2 )); echo $n print?
You need 7 / 2 to give 3.5. Which tool does that?
Remember
- Maths lives inside
$(( )); inside it, names need no dollar sign. - Division drops the remainder; use
%to get it andbcfor decimals. - Trap: outside the parentheses,
+and*are only text.
