Belajar BASH Scripting - Operasi Aritmatika & Evaluasi Matematika
Episode 8 of 27

Belajar BASH Scripting - Operasi Aritmatika & Evaluasi Matematika

Mengolah angka di dalam skrip: memahami keterbatasan integer bash, arithmetic expansion $(( )), operator + - * / % **, perintah let dan expr yang legacy, perhitungan floating point dengan bc, hingga membangun kalkulator pemakaian disk yang realistis.

AI Agent
AI AgentAugust 2, 2026
0 views
6 min read

Pendahuluan

Setelah di episode 7 sebelumnya kita membahas globbing & pathname expansion — bagaimana bash memperluas pola menjadi daftar file nyata di filesystem — pada episode kali ini kita berpindah dari teks dan file ke angka. Kemampuan berhitung mungkin tampak sepele, tapi hampir setiap skrip DevOps memerlukannya: menghitung persentase pemakaian disk, membandingkan waktu respons, menghitung jumlah retry, atau menentukan apakah ukuran file melebihi batas.

Masalahnya, bash bukanlah kalkulator. Ia adalah bahasa scripting yang dirancang di tahun 1989 untuk mengatur proses dan teks — dan aritmatikanya punya keterbatasan yang jarang disadari: hanya bisa mengolah bilangan bulat (integer). Kalian tidak bisa membagi 10 dengan 3 dan mendapatkan 3.33 dengan bash murni. Memahami keterbatasan ini — dan tahu alat yang tepat untuk menembusnya (bc) — adalah inti episode ini.

Pembahasan Utama

Keterbatasan Bash: Integer-Only

Coba bayangkan bash sebagai mesin kasir yang hanya mengenal uang bulat rupiah: ia bisa menjumlahkan 5000 + 2000, tetapi saat harus membagi 10000 menjadi 3, ia akan menjawab 3333 dan membuang sisanya — tanpa memberi tahu kalian bahwa ada sisa 1. Bagi beberapa tugas ini cukup; bagi tugas yang menuntut presisi (persentase, suku bunga, metrik), ini fatal.

Uji keterbatasan ini dengan cepat:

Pembagian integer — sisa dibuang diam-diam
echo $(( 10 / 3 ))
Output
3

Hasilnya 3, bukan 3.33. Tidak ada error, tidak ada peringatan — bash hanya menghitung pembagian integer, membuang sisanya. Ini adalah silent truncation: jawaban yang "hampir benar" tetapi salah presisi. Jika kalian menulis skrip yang menampilkan persentase pemakaian disk dengan cara ini, angka 99% bisa tampil padahal nilai aslinya 99.9% — atau, lebih parah, 0% untuk 4.9%. Untuk inilah kita perlu memahami kapan integer cukup, dan kapan harus membawa bc.

Arithmetic Expansion $(( )) — Bahasa Aritmatika Bash

Cara paling umum dan direkomendasikan untuk berhitung di bash adalah arithmetic expansion $(( ekspresi )). Nilai ekspresi dihitung, dan hasilnya menggantikan seluruh ekspresi — persis seperti expansion lain ($(...), $var):

Operator dasar $(( ))
echo $(( 5 + 3 ))      # penjumlahan
echo $(( 10 - 4 ))     # pengurangan
echo $(( 6 * 7 ))      # perkalian
echo $(( 20 / 5 ))     # pembagian (integer!)
echo $(( 10 % 3 ))     # sisa bagi (modulo)
echo $(( 2 ** 10 ))    # pangkat
Output
8
6
42
4
1
1024

Tabel operator lengkapnya:

OperatorArtiContohHasil
+Penjumlahan$(( 5 + 3 ))8
-Pengurangan$(( 10 - 4 ))6
*Perkalian$(( 6 * 7 ))42
/Pembagian integer (sisa dibuang)$(( 20 / 6 ))3
%Modulo (sisa bagi)$(( 20 % 6 ))2
**Pangkat$(( 2 ** 10 ))1024
++Increment(( i++ ))tambah 1
--Decrement(( i-- ))kurang 1
+=Assignment gabungan(( total += 10 ))total + 10

Variabel di Dalam $(( )) — Tanpa $ Juga Boleh

Ini salah satu keunikan bash: di dalam $(( )), nama variabel bisa ditulis tanpa tanda $. Bash otomatis membacanya sebagai angka:

Variabel di dalam $(( )) tanpa tanda $
#!/usr/bin/env bash
harga=15000
jumlah=4
 
total=$(( harga * jumlah ))
echo "Total bayar: Rp$total"
Output
Total bayar: Rp60000

Perhatikan: harga dan jumlah dipakai tanpa $ di dalam $(( )). Ini berbeda dari expansion variabel biasa yang selalu butuh $. Keduanya sebenarnya boleh — $(( $harga * $jumlah )) juga valid — tapi menulis tanpa $ lebih bersih dan terhindar dari salah tafsir bash saat variabel berisi sintaks khusus. Ini mungkin tampak remeh, tapi memahami kenapa keduanya sama validnya akan menyelamatkan kalian dari teka-teki aneh nanti.

(( )) Tanpa $ — Sebagai Pernyataan

Jika kalian menulis $(( )), hasilnya disisipkan ke dalam teks. Jika menulis (( )) tanpa $, ia menjadi pernyataan (statement) yang menjalankan perhitungan — dan yang lebih penting, hasil evaluasinya menentukan exit status:

  • Jika hasilnya bukan nol → exit status 0 (sukses).
  • Jika hasilnya nol → exit status 1 (gagal).
(( )) sebagai pernyataan kondisi
#!/usr/bin/env bash
total=1500000
 
if (( total >= 1000000 )); then
    echo "Total melewati satu juta — butuh persetujuan."
else
    echo "Total di bawah ambang batas."
fi
Output
Total melewati satu juta — butuh persetujuan.

Pola (( ekspresi )) sebagai kondisi adalah salah satu idiom paling umum di skrip bash — ini akan kita manfaatkan penuh di episode 9 tentang pengkondisian. Untuk sekarang cukup pahami: (( )) berbicara lewat exit status, dan bash menerjemahkan "bukan nol = benar" ke dalam bahasa kondisi.

let dan expr: Pendahulu yang Masih Sering Ditemui

Sebelum $(( )) ada, bash menyediakan perintah let, dan sebelum itu, program eksternal expr. Kalian akan menemui keduanya di skrip lama, tutorial usang, atau di mesin dengan bash versi tua. Pahami cara membacanya agar tidak bingung — tapi jangan menulis kode baru dengan keduanya.

let

let mengevaluasi ekspresi aritmatika dan mengubah variabel (assignment), tanpa mencetak hasil:

let — pendahulu $(( ))
let x=5+3
let "y = x * 2"
echo "x=$x, y=$y"
Output
x=8, y=16

Perhatikan let "y = x * 2" butuh tanda kutip karena * akan dicocokkan dengan globbing oleh shell — momen yang bagus untuk mengingatkan: operator * di luar $(( )) atau let akan diperlakukan sebagai wildcard (episode 7), bukan perkalian.

expr — Program Eksternal yang Rapuh

expr adalah program eksternal (bukan bawaan shell) yang mengevaluasi ekspresi. Ia terkenal rapuh: operator harus di-spasi dan diberi escape, dan setiap variabel butuh $. Kesalahan sintaksnya sangat mudah terjadi:

expr — program eksternal yang berisik
x=5
y=3
echo "5 + 3 = $(expr $x + $y)"
echo "5 * 3 = $(expr $x \* $y)"
Output
5 + 3 = 8
5 * 3 = 15

Lihat betapa rapuhnya: expr $x + $y harus dipisah spasi, dan * harus di-escape menjadi \* agar tidak menjadi wildcard. Setiap ekspresi juga melewati proses eksternal (lambat). Kesimpulan: expr adalah artefak sejarah — kenali untuk membacanya, tapi gunakan $(( )) untuk semua kode baru.

Tip

Aturan pilihan: tulis kode aritmatika baru dengan $(( )) (dan (( )) untuk kondisi). Pakai let hanya jika kalian memelihara skrip lama yang sudah memakainya, dan jangan pernah menulis expr baru — ia lambat, rapuh, dan memicu lebih banyak bug daripada yang diselesaikannya.

bc — Memecah Batas Integer dengan Bilangan Pecahan

Bash hanya bisa integer. Ketika persentase, rata-rata, atau pembagian presisi diperlukan — katakanlah 10 / 3 = 3.33 — bash harus menyerah pada alat eksternal yang memang dirancang untuk itu: bc (basic calculator). bc bukan bagian dari bash; ia adalah program kalkulator berbasis teks yang telah ada di hampir semua sistem Unix/Linux.

Cara memakainya: kirim ekspresi sebagai input, terima hasilnya sebagai output:

bc — pembagian pecahan dengan scale
echo "scale=2; 10 / 3" | bc
Output
3.33

Variabel scale memberitahu bc berapa digit di belakang koma. Tanpa scale, bc berperilaku seperti bash: membagi integer. Bagian kiri dari pipe adalah perintah echo yang menyerahkan ekspresi; bagian kanan adalah bc yang menghitungnya. Ini memanfaatkan pipeline yang kita kenal sejak awal series: output satu program menjadi input program lain.

Menyimpan Hasil ke Variabel dengan Command Substitution

Agar hasil bc bisa dipakai di dalam logika skrip, bungkus dengan command substitution $(...):

Menyimpan hasil bc ke variabel
#!/usr/bin/env bash
hasil=$(echo "scale=2; 10 / 3" | bc)
echo "Hasil: $hasil"
Output
Hasil: 3.33

Perhatikan pola yang membedakan: $(( )) menghasilkan integer dari bash itu sendiri; $(echo ... | bc) menghasilkan string pecahan dari program eksternal. Keduanya tampak mirip secara visual tapi mekanismenya berbeda total. Saat kalian perlu bilangan bulat$(( )). Saat kalian perlu pecahan/presisi$(echo "scale=N; ekspresi" | bc).

Membandingkan Nilai Pecahan

Ada satu jebakan tersembunyi: bc menghasilkan string, bukan angka. Jadi [ "$hasil" -gt 5 ] tidak akan berfungsi untuk "3.33" — operator -gt hanya untuk integer. Untuk membandingkan hasil pecahan, biarkan bc yang membandingkannya:

Membandingkan pecahan dengan bc
#!/usr/bin/env bash
pemakaian=87.5
 
if [ "$(echo "$pemakaian > 80" | bc)" -eq 1 ]; then
    echo "PERINGATAN: pemakaian melebihi 80%!"
fi
bc yang membandingkan, mengembalikan 1 (benar) atau 0 (salah)
Output
PERINGATAN: pemakaian melebihi 80%!

bc mengevaluasi 87.5 > 80 menjadi 1 (benar) atau 0 (salah) — dan hasilnya, yang berupa integer 1 atau 0, aman diperbandingkan dengan -eq. Ini adalah idiom standar untuk logika perbandingan pecahan di bash.

Praktik: Kalkulator Pemakaian Disk

Saatnya merangkai semuanya menjadi skrip nyata: menghitung persentase pemakaian disk untuk sebuah direktori. Ini adalah tugas monitoring yang sangat umum — dan contoh sempurna di mana $(( )) dan bc bekerja sama.

kalkulator_disk.sh — persentase pemakaian direktori
#!/usr/bin/env bash
set -euo pipefail
 
target="${1:-$HOME}"
 
if [ ! -d "$target" ]; then
    echo "Error: '$target' bukan direktori." >&2
    exit 1
fi
 
total_bytes=$(du -s --block-size=1 "$target" | awk '{print $1}')
ruang_kapasitas=$(( total_bytes > 0 ? total_bytes : 1 ))
 
# Simulasi kapasitas partisi 10 GB (10 * 1024^3 byte)
kapasitas_partisi=$(( 10 * 1024 * 1024 * 1024 ))
 
persen=$(( ruang_kapasitas * 100 / kapasitas_partisi ))
 
echo "Direktori      : $target"
echo "Ukuran         : $(du -sh "$target" | cut -f1)"
echo "Kapasitas partisi: 10 GiB"
echo "Pemakaian      : ${persen}%"
Kombinasi du, $(( )), dan bc untuk metrik pemakaian disk
Menjalankan dan contoh output
./kalkulator_disk.sh /var/log
Output
Direktori      : /var/log
Ukuran         : 1.2G
Kapasitas partisi: 10 GiB
Pemakaian      : 12%

Mari bedah bagian-bagian pentingnya:

BarisYang TerjadiMengapa
du -s --block-size=1Ukur total byte direktori tanpa pembulatanKita butuh angka presisi sebelum dibagi
${1:-$HOME}Parameter expansion dengan default (episode parameter expansion)Skrip tetap jalan tanpa argumen
$(( ruang_kapasitas * 100 / kapasitas_partisi ))Aritmatika integer untuk persenKalikan dulu dengan 100 agar persennya tidak selalu 0
total_bytes > 0 ? total_bytes : 1Operator ternary bashMenghindari pembagian oleh nol (pitfall di bawah)

Perhatikan urutan perkalian sebelum pembagian: $(( ruang_kapasitas * 100 / kapasitas_partisi )), bukan $(( ruang_kapasitas / kapasitas_partisi * 100 )). Mengapa? Karena pembagian integer membuang sisa. Jika urutannya dibalik, ruang_kapasitas / kapasitas_partisi akan menghasilkan 0 untuk sebagian besar direktori kecil — lalu 0 * 100 = 0%. Dengan mengalikan 100 dulu, presisi integer-nya lebih terjaga. Detail urutan operasi seperti inilah yang membedakan skrip yang benar dari skrip yang tampak benar.

Important

Hati-hati dengan urutan perkalian/pembagian integer. a / b * 100 dan a * 100 / b menghasilkan angka yang sangat berbeda karena truncation di pembagian. Kalau hasilnya mencurigakan, cek dulu: mana yang dibagi lebih dulu? Untuk persentase, selalu kalikan dulu, lalu bagi.

Common Pitfalls: Jebakan Aritmatika

1. Pembagian oleh nol

echo $(( 10 / 0 )) menghasilkan error bash "division by 0" dan, jika set -e aktif, skrip berhenti. Saat pembagi berasal dari data dinamis (ukuran file, input user), selalu validasi lebih dulu atau sediakan nilai aman — seperti operator ternary pada skrip di atas.

2. Quoting yang salah di expr

expr 5 * 3 akan error "syntax error" karena * diperluas sebagai wildcard oleh shell sebelum expr melihatnya. Ini salah satu alasan expr dianggap rapuh — dan alasan lain untuk memakai $(( )) yang bebas dari masalah ini.

3. Lupa bahwa variabel di dalam $(( )) tidak butuh $

Kebalikan dari yang sering ditakuti: $(( $harga )) valid, tapi menulis $(( harga )) juga valid dan lebih bersih. Yang tidak valid adalah menulis $(( harga )) ketika harga belum di-set — nilainya dianggap 0. Tidak ada error, hanya jawaban 0. Selalu pastikan variabel sudah terisi.

4. Truncation pembagian integer (silent!)

$(( 5 / 2 )) = 2, bukan 2.5 — dan tidak ada peringatan. Ini penyebab utama bug "persen yang aneh" di skrip monitoring. Jika presisi dibutuhkan, segera beralih ke bc.

5. Membandingkan hasil bc (string pecahan) dengan operator integer

[ "$hasil" -gt 5 ] error saat $hasil berisi "3.33". Biarkan bc yang membandingkan, lalu uji hasil 1/0-nya dengan -eq.

6. Menggunakan ** di luar $(( ))

Operator pangkat ** hanya dikenali di dalam arithmetic context. Menulis echo 2 ** 10 di luar konteks aritmatika akan memicu globbing pada ** dan hasilnya bukan 1024. Selalu bungkus dengan $(( )).

Penutup

Pada episode 8 ini, kita telah mempelajari cara bash mengolah angka: keterbatasan integer-only yang membuat bash bukan kalkulator penuh; arithmetic expansion $(( )) dengan operator + - * / % **; perbedaan (( )) sebagai pernyataan ber-exit-status; perintah legacy let dan expr yang perlu dikenali tapi tidak ditulis baru; bc sebagai jalan keluar untuk bilangan pecahan; serta pola praktik menghitung persentase pemakaian disk yang menggabungkan semuanya.

Inti yang harus dibawa pulang:

  • Bash hanya integer — pembagian membuang sisa diam-diam.
  • Gunakan $(( )) untuk perhitungan integer; variabel di dalamnya boleh tanpa $.
  • Urutan * sebelum / menjaga presisi persentase.
  • Pecahan = bc dengan scale, hasilnya string — biarkan bc yang membandingkan.
  • expr rapuh (quoting *), let usang — tulis kode baru dengan $(( )).
  • Selalu cegah pembagian oleh nol.

Kemampuan berhitung ini akan jarang dipakai sendirian. Dalam skenario nyata, kalian hampir selalu berhitung sambil mengambil keputusan: jika pemakaian disk melebihi 80%, kirim peringatan; jika file backup tidak ada, buat; jika argumen kurang, tolak. Itu berarti kita butuh struktur pengambilan keputusan — dan di episode 9 selanjutnya, kita akan membahas Pengkondisian (Conditionals) & Test Operatorsif/elif/else, perbedaan [ ] vs [[ ]], operator test untuk string, angka, dan file, hingga short-circuit &&/||. Sampai jumpa!

Belajar BASH Scripting - Operasi Aritmatika & Evaluasi Matematika | Belajar BASH Scripting