Shell Script #6 - Mathematical Operations
We continue the shell scripting series with mathematical operations. This topic will be quite simple for those familiar with programming languages. However, we will still cover some bash-specific points.
The GitHub repository where I share code examples: Shell Scripting 101
let Expression
By examining the following code and output, you will see that the values assigned to the variables are not treated as mathematical expressions, but rather, as string literals:
#! /bin/bash
#İki farklı değişken tanımlıyoruz:
sayi1=35
sayi2=42
#Bu değişkenleri toplamayı denersek, sonuç pek de tatmin edici olmuyor:
toplam=$sayi1+$sayi2
echo $toplam
Output:
It seems like the requested output has been provided. The expression sayi1 (35) + sayi2 (42) has been printed to the screen. However, that was not our intention.
Here, the expression that comes to our aid is "let". When we ask our shell what let is, we get a quite explanatory response:
[root@localhost ShellScripting101]# type let
let bir kabuk yerleşiğidir
[root@localhost ShellScripting101]# help let
let: let arg [arg ...]
Evaluate arithmetic expressions.
Evaluate each ARG as an arithmetic expression. Evaluation is done in
fixed-width integers with no check for overflow, though division by 0
is trapped and flagged as an error. The following list of operators is
grouped into levels of equal-precedence operators. The levels are listed
in order of decreasing precedence.
id++, id-- variable post-increment, post-decrement
++id, --id variable pre-increment, pre-decrement
-, + unary minus, plus
!, ~ logical and bitwise negation
** exponentiation
*, /, % multiplication, division, remainder
+, - addition, subtraction
<<, >> left and right bitwise shifts
<=, >=, <, > comparison
==, != equality, inequality
& bitwise AND
^ bitwise XOR
| bitwise OR
&& logical AND
|| logical OR
expr ? expr : expr
conditional operator
=, *=, /=, %=,
+=, -=, <<=, >>=,
&=, ^=, |= assignment
Shell variables are allowed as operands. The name of the variable
is replaced by its value (coerced to a fixed-width integer) within
an expression. The variable need not have its integer attribute
turned on to be used in an expression.
Operators are evaluated in order of precedence. Sub-expressions in
parentheses are evaluated first and may override the precedence
rules above.
Exit Status:
If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
Now, let's examine the example below:
#! /bin/bash
#İki farklı değişken tanımlıyoruz:
sayi1=35
sayi2=42
#İfadelerin bir matematiksel ifade olarak görülmesini sağlamak için let kullanırız:
let toplam=$sayi1+$sayi2
echo $toplam
#Ekrana 77 yazacaktır.
As shown above, we used "let" to indicate that the value to be assigned to the "toplam" variable should be a mathematical expression. However, when defining our variables, we did not use "let." But we created these variables to be used in mathematical operations. For both the readability of our code and because of potential uncertainties that we might encounter later on, it is beneficial to define everything we will use in mathematical expressions with "let."
In the following code example, you can see some basic mathematical operations:
#! /bin/bash
#Değişken tanımları:
let sayi1=35
let sayi2=42
#Toplama işlemi:
let toplama=$sayi1+$sayi2
#Çıkarma işlemi:
let cikarma=$sayi1-$sayi2
#Çarpma işlemi:
let carpma=$sayi1*$sayi2
#Bölme işlemi (Buraya dikkat. Bash tam bölme işlemi yapar, virgüllü sayılarla ilgilenmez):
let bolme=$sayi1/$sayi2
#Kalan bulma (modulus) işlemi:
let modulus=$sayi1%$sayi2
#Üs alma (Buraya dikkat. Bu işleç, bash'te çalışıyor olabilir ancak her shell'de çalışacağının garantisi yok):
let us=$sayi1**3
echo "$sayi1+$sayi2 işleminin sonucu: $toplama"
echo "$sayi1-$sayi2 işleminin sonucu: $cikarma"
echo "$sayi1*$sayi2 işleminin sonucu: $carpma"
echo "$sayi1/$sayi2 işleminin sonucu: $bolme"
echo "$sayi1%$sayi2 işleminin sonucu: $modulus"
echo "$sayi1^3 işleminin sonucu: $us"
You can see the output of the code below:
[root@localhost ShellScripting101]# ./7-matematiksel_islemler.sh
35+42 işleminin sonucu: 77
35-42 işleminin sonucu: -7
35*42 işleminin sonucu: 1470
35/42 işleminin sonucu: 0
35%42 işleminin sonucu: 35
35^3 işleminin sonucu: 42875
Division operation is a bit annoying, isn't it? Bash cannot perform calculations with floating-point numbers. Therefore, we need to get help from a different tool.
Mathematical Operations with Floating-Point Numbers in Shell Scripts
Bash itself cannot perform operations with floating-point numbers. Therefore, we need to use other tools. The tools you will use depend on your system and creativity. In this article, I will use the "bc" tool.
The bc Program
bc is a calculator language. Don't immediately think of Blitzcrank :) It can calculate your expressions with precision and return the result. It's highly likely that this tool is already installed on your system:
[root@localhost ShellScripting101]# whatis bc
bc (1) - An arbitrary precision calculator language
[root@localhost ShellScripting101]# which bc
/usr/bin/bc
When using bc, we will use the "-l" parameter to include the math libraries. The usage is as follows:
#! /bin/bash
#Değişken tanımları:
#Buraya dikkat. let kullanamam.
#Çünkü bash, let'i matematiksel ifadelerde kullanılıyor
#ve ondalıklı sayıları tanımadığı için hata veriyor:
sayi1=29.2
sayi2=13.75
#Toplama işlemi:
#Burada, daha önceki örneklerde de karşımıza çıkan "command substitution" kullanılıyor.
#$() içerisinde yapılan işlemin sonucu, dışarıdaki değişkene atılıyor.
#$sayi1+$sayi2 ifadesi echo'lanıyor ve pipe üzerinden bc programına gönderiliyor.
#Dikkat edin, yine let yok. Çünkü bash'e göre, ortada matematiksel bir ifade yok:
toplama=$(echo "$sayi1+$sayi2" | bc -l)
#Çıkarma işlemi:
cikarma=$(echo "$sayi1-$sayi2" | bc -l)
#Çarpma işlemi:
carpma=$(echo "$sayi1*$sayi2" | bc -l)
#Bölme işlemi:
bolme=$(echo "$sayi1/$sayi2" | bc -l)
#Kalan bulma (modulus) işlemi:
modulus=$(echo "$sayi1%$sayi2" | bc -l)
#Üs alma (Buraya dikkat. İşlemi bc programına yaptıracağımız için, üs alma operatörü olarak ^ kullanıyoruz:
us=$(echo "$sayi1^3" | bc -l)
echo "$sayi1+$sayi2 işleminin sonucu: $toplama"
echo "$sayi1-$sayi2 işleminin sonucu: $cikarma"
echo "$sayi1*$sayi2 işleminin sonucu: $carpma"
echo "$sayi1/$sayi2 işleminin sonucu: $bolme"
echo "$sayi1%$sayi2 işleminin sonucu: $modulus"
echo "$sayi1^3 işleminin sonucu: $us"
Here's the more elegant version:
Exponentiation
As I mentioned in the code examples, we used the "**" characters for exponentiation in bash. However, when using "bc -l", we use the "^" character to perform exponentiation.
[root@localhost ShellScripting101]# ./8-bc_ornekleri.sh
29.2+13.75 işleminin sonucu: 42.95
29.2-13.75 işleminin sonucu: 15.45
29.2*13.75 işleminin sonucu: 401.500
29.2/13.75 işleminin sonucu: 2.12363636363636363636
29.2%13.75 işleminin sonucu: .0000000000000000000500
29.2^3 işleminin sonucu: 24897.088
Division operation seems a bit tricky again, doesn't it?
I won't go into much detail on the topic, but here's the keyword: "scale". When using the bc program, you can change the scale value to determine how many decimal places will be displayed:
#! /bin/bash
#scale örneği.
#Virgülden sonra kaç basamak görüntüleneceğini belirtebilirsiniz:
birinci_sayi=22
ikinci_sayi=7
bolum=$(echo "$birinci_sayi/$ikinci_sayi" | bc -l)
echo $bolum
bolum=$(echo "scale=2; $birinci_sayi/$ikinci_sayi" | bc -l)
echo $bolum
Outputs will be like this:
expr Program
The expr program is a tool that evaluates expressions given to it. I could say it "evaluates Expressions," but that doesn't sound quite right.
expr's ability to evaluate extends to mathematical operators as well.
#! /bin/bash
#expr kullanımı:
#expr programı, çıktıyı ekrana verir.
#Ancak bu davranışı değiştirmek için command substitution kullanılabilir.
#Önemli bir nokta daha. expr programı, işleçler arasında boşluk karakteri görmek ister.
#Hatırlarsanız, bash'te ise tam tersine boşluk görmek istemiyorduk.
#Değişken tanımları:
sayi1=19
sayi2=28
#İki değeri topla ve sonucu yaz:
expr $sayi1+$sayi2
#Ekrana 19+28 yazar.
expr $sayi1 + $sayi2
#Ekrana 47 yazar.
#İfadeyi yorumla ve sonucu değişkene ata:
toplam=$(expr $sayi1 + $sayi2)
#toplam değişkeninin değeri 47 oldu.
#Ekrana toplam = 47 yazar.
echo toplam = $toplam
#Çarpma işlemi biraz sorunlu.
#Command substitution sırasında çarpma işlemi için * karakterini kullanamayız.
#Çünkü * karakteri, bash için bir özel karkater (wildcard olarak kullanıyoruz hatırlarsanız)
#Dolayısıyla bir escape yapmamız gerekecek:
expr $sayi1*$sayi2
#Ekrana 19*28 yazar.
expr $sayi1 * $sayi2
#Syntax hatası
expr $sayi1 \* $sayi2
#Ekrana 532 yazar
carpim=$(expr $sayi1 \* $sayi2)
echo "19 * 28 = $carpim"
#Ekrana 19 * 28 = 532 yazar
Output of the code will be like this:

