Belajar BASH Scripting - Pengkondisian (Conditionals) & Test Operators
Episode 9 of 27

Belajar BASH Scripting - Pengkondisian (Conditionals) & Test Operators

Memberi skrip kemampuan mengambil keputusan: struktur if/elif/else/fi berbasis exit status, perbedaan test [ ] (POSIX) dengan [[ ]] (bash), operator test untuk string, angka, dan file, hingga short-circuit && dan || beserta pola skrip monitoring yang siap pakai.

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

Pendahuluan

Setelah di episode 8 sebelumnya kita membahas operasi aritmatika — menghitung dengan $(( )) dan bc — pada episode kali ini kita menutup fondasi dasar ini dengan struktur yang membuat semua perhitungan itu berarti: pengkondisian. Aritmatika tanpa keputusan hanyalah angka; keputusan tanpa aritmatika hanya asumsi. Gabungkan keduanya, dan skrip kalian berubah dari sekadar mengeksekusi perintah menjadi berpikir.

Sejak episode 5, kalian sudah melihat sekilas banyak idiom yang akan kita bedah sekarang: [ $# -ne 2 ] untuk validasi argumen, [ -z "$nama" ] untuk cek input kosong, (( total >= 1000000 )) untuk ambang batas. Episode ini akan menyatukan semuanya: memahami mengapa struktur if di bash bekerja berdasarkan exit status, mengapa [[ ]] lebih aman daripada [ ], dan operator test untuk string, angka, dan file bisa menangkap hampir semua kondisi di dunia nyata.

Pembahasan Utama

if, elif, else, fi — Keputusan Berbasis Exit Status

Struktur if di bash berbeda dari bahasa pemrograman lain. Di Python atau JavaScript, if mengharapkan nilai boolean. Di bash, if mengharapkan perintah — dan ia mengambil keputusan berdasarkan exit status perintah itu: 0 berarti "benar", bukan 0 berarti "salah".

Anatomi dasar if
#!/usr/bin/env bash
if command_yang_dijalankan; then
    echo "Berhasil (exit 0)"
elif perintah_lain; then
    echo "Kondisi kedua terpenuhi"
else
    echo "Semua kondisi gagal"
fi

Perhatikan struktur lengkapnya: if ... then ... elif ... then ... else ... fi. fi adalah kebalikan dari if — penutup blok. Kata kunci then wajib ada setelah kondisi. Dan karena dasarnya adalah exit status, apa pun yang mengembalikan exit status bisa menjadi kondisi — bukan hanya test. Contoh paling nyata:

if langsung memakai exit status perintah
#!/usr/bin/env bash
if grep -q "error" /var/log/app.log; then
    echo "ADA baris error di log — perlu investigasi."
else
    echo "Tidak ada error ditemukan."
fi

grep -q mencetak apa pun (bendera -q = quiet), dan mengembalikan 0 jika pola ditemukan, 1 jika tidak. Karena if hanya membaca exit status, kalian tidak perlu menulis if [ $(grep ...) ]; then — cukup serahkan perintahnya langsung. Inilah yang membuat bash begitu elegan: kondisi adalah perintah, bukan tipe data.

Mengapa Bentuk if [ ... ]; then?

Kalau if berbasis perintah, lalu apa itu [ ... ]? Jawabannya: [ adalah sebuah perintah — nama lain dari program test. Ia mengevaluasi ekspresi dan mengembalikan exit status. Jadi if [ "$a" = "b" ]; then dibaca sebagai: jalankan perintah test dengan argumen "$a", =, "b", lalu gunakan exit statusnya. Ini menjelaskan banyak keanehan sintaks bash — seperti kenapa spasi di dalam [ ] wajib ada:

Spasi wajib — [ ] adalah perintah
[ "$a" = "b" ]   # benar — argumen terpisah: [, "$a", =, "b", ]
[ "$a" = "b"]    # salah — "b]" menjadi satu argumen, error "unexpected token"
[ "$a"="b" ]     # salah — seluruh ekspresi menjadi satu argumen

Karena [ adalah perintah, setiap bagian ekspresi harus menjadi argumen terpisah yang dipisahkan spasi. Ini juga alasan kenapa test dan [ bisa saling menggantikan: test "$a" = "b" sama persis dengan [ "$a" = "b" ]. Tanda ] terakhir hanyalah argumen penutup yang membuat sintaksnya terasa "seperti kurung".

[ ] vs [[ ]]: Dua Dunia Berbeda

Inilah salah satu keputusan desain paling penting yang harus kalian buat sebagai penulis skrip bash: memakai [ ] (test POSIX) atau [[ ]] (ekstensi bash). Keduanya terlihat mirip, tapi perilakunya berbeda fundamental.

[ ] — POSIX, Portable, Tapi Rapuh

[ ] adalah perintah eksternal/internal yang mematuhi standar POSIX — artinya ia portable: bekerja di sh, dash, dan semua shell. Namun portabilitas ini datang dengan harga:

  • Word splitting tetap terjadi pada variabel yang tidak dikutip.
  • Tanpa dukungan regex — hanya perbandingan string sederhana.
  • && dan || tidak dikenali di dalamnya (mereka dipisah oleh shell sebagai operator perintah).

[[ ]] — Ekstensi Bash, Lebih Kuat dan Lebih Aman

[[ ]] adalah keyword bawaan bash — bukan perintah eksternal. Karena itu ia memahami sintaks dengan cara yang lebih "pintar":

  • Tanpa word splitting dan globbing — variabel tidak perlu dikutip (meski kutip tetap baik).
  • && dan || bekerja di dalam sebagai operator logika ekspresi.
  • Regex dengan =~ — kalian sudah melihat sekilas di episode 6.

Bandingkan:

Perilaku saat variabel kosong atau ber-spasi
#!/usr/bin/env bash
var=""   # variabel kosong
 
# [ ] — Wajib kutip; tanpa kutip, error "unary operator expected"
if [ "$var" == "x" ]; then echo "x"; fi
 
# [[ ]] — Lebih toleran dan lebih aman
if [[ $var == "x" ]]; then echo "x"; fi
Kenapa [ ] error tanpa kutip
bash: [: x: unary operator expected

Saat $var kosong dan ditulis tanpa kutip, [ $var == "x" ] menjadi [ == "x" ] — dan test bingung karena argumen pertamanya adalah operator ==, bukan nilai. Sementara [[ $var == "x" ]] memperlakukan $var sebagai satu token apa pun isinya — tanpa perlu kutip. Inilah mengapa tim-tim skrip profesional menetapkan aturan: gunakan [[ ]] dalam skrip bash dan simpan [ ] hanya untuk skrip yang harus portable ke sh.

Important

Pilih [[ ]] untuk skrip bash (shebang #!/usr/bin/env bash) — ia lebih aman (tanpa word splitting), mendukung regex =~, dan operator &&/|| di dalamnya. Pakai [ ] hanya jika kalian menulis skrip yang benar-benar harus berjalan di shell POSIX murni (sh). Konsistensi ini menghilangkan satu kelas bug yang selama ini paling sering menimpa pemula.

Contoh: && dan || di Dalam [[ ]]

Karena [[ ]] memahami operator logika, menggabungkan beberapa kondisi menjadi alami:

Kombinasi kondisi di dalam [[ ]]
#!/usr/bin/env bash
user="root"
env="produksi"
 
if [[ $user == "root" && $env == "produksi" ]]; then
    echo "Akses DIBERIKAN — kombinasi berbahaya, tetapi valid."
elif [[ $user == "root" || $env == "staging" ]]; then
    echo "Akses dengan peringatan."
else
    echo "Akses ditolak."
fi
Output
Akses DIBERIKAN — kombinasi berbahaya, tetapi valid.

Menggunakan [ ], ekspresi yang sama butuh penulisan berantai dan kutip tambahan: [ "$user" = "root" ] && [ "$env" = "produksi" ]. Keduanya bekerja, tapi [[ ]] jauh lebih mudah dibaca — dan keterbacaan adalah fitur, bukan kemewahan.

Test Operators: String, Angka, dan File

Sekarang kita masuk ke perangkat keras dari pengkondisian: operator-operator test. Ketiganya bekerja sama di [ ] dan [[ ]] (dengan sedikit perbedaan yang sudah dibahas).

Operator String

Test string: kosong, tidak kosong, sama, beda
#!/usr/bin/env bash
nama="Arman"
 
if [[ -z "$nama" ]]; then echo "String kosong."; fi
if [[ -n "$nama" ]]; then echo "String tidak kosong."; fi
if [[ "$nama" == "Arman" ]]; then echo "Sama persis."; fi
if [[ "$nama" != "Budi" ]]; then echo "Berbeda dengan 'Budi'."; fi
Output
String tidak kosong.
Sama persis.
Berbeda dengan 'Budi'.
OperatorBenar jika...Kontra-intuitif?
-z "$var"string kosong (zero-length)Ya — -z = "nol panjang", bukan "ada nilai"
-n "$var"string tidak kosongYa — kebalikan intuitif dari -z
$a == $bdua string samaTidak
$a != $bdua string berbedaTidak

Operator Angka

Untuk angka, jangan memakai > atau < di dalam [ ] — mereka adalah operator redirection shell, bukan perbandingan! Bash menyediakan operator kata-kata khusus:

Test angka: -eq -ne -gt -ge -lt -le
#!/usr/bin/env bash
pemakaian=87
 
if (( pemakaian >= 90 )); then
    echo "KRITIS: pemakaian $pemakaian%."
elif (( pemakaian >= 80 )); then
    echo "PERINGATAN: pemakaian $pemakaian%."
else
    echo "Normal: pemakaian $pemakaian%."
fi
OperatorArti
-eqequal — sama dengan
-nenot equal — tidak sama
-gtgreater than — lebih besar
-gegreater or equal — lebih besar atau sama
-ltless than — lebih kecil
-leless or equal — lebih kecil atau sama

Perhatikan contoh di atas menggunakan (( )) dari episode 8 — ketika hanya membandingkan integer, (( )) adalah pilihan yang lebih bersih daripada [ "$pemakaian" -ge 90 ]. Tapi kalian akan sering menemui bentuk [ "$x" -ge 90 ] di skrip lain, jadi menguasai kedua sintaks itu penting. Dan bila nilai bisa pecahan (dari bc), ingat pelajaran episode 8: biarkan bc yang membandingkan.

Operator File dan Direktori

Inilah yang membuat bash hebat untuk otomasi: bash bisa menanyakan properties file langsung, tanpa perlu memanggil program lain.

Test file: ada? direktori? bisa baca?
#!/usr/bin/env bash
file="/etc/nginx/nginx.conf"
 
if [[ -f "$file" ]]; then
    echo "Ada file: $file"
elif [[ -d "$file" ]]; then
    echo "Ini direktori, bukan file biasa."
fi
 
if [[ -r "$file" ]]; then
    echo "File bisa dibaca."
fi
OperatorBenar jika...Skenario Nyata
-e pathpath ada (file, dir, symlink, apa pun)Cek keberadaan sebelum akses
-f pathpath adalah file biasa-f = "file" — kunci konfigurasi
-d pathpath adalah direktoriCek sebelum cd atau loop glob
-r pathfile bisa dibacaValidasi izin sebelum membaca
-w pathfile bisa ditulisCek sebelum menulis log
-x pathfile bisa dieksekusiCek biner/skrip sebelum menjalankan
-s pathfile ada dan tidak kosong-s = "size > 0" — log yang kosong

Tip

Banyak pemula memakai -e dan -f secara bergantian — padahal berbeda. -e benar untuk path apa pun (termasuk symlink dan direktori); -f khusus file biasa. Saat kalian menulis if [ -f "$dir" ] untuk variabel yang sebenarnya direktori, kondisi itu akan selalu salah. Tanyakan pada diri sendiri: apa yang persis ingin kuverifikasi? lalu pilih operator yang sesuai — presisi ini yang membuat skrip bisa dipercaya.

Short-Circuit && dan ||

Selain if, bash punya cara ringkas untuk pengambilan keputusan: short-circuit evaluation. Pada pipeline, cmd1 && cmd2 menjalankan cmd2 hanya jika cmd1 sukses; cmd1 || cmd2 menjalankan cmd2 hanya jika cmd1 gagal.

&& dan || sebagai pengambil keputusan
#!/usr/bin/env bash
mkdir -p /tmp/backup && echo "Direktori dibuat."
 
[ -d /tmp/backup ] || echo "Direktori tidak ada — buat dulu!"
Output
Direktori dibuat.
Direktori tidak ada — buat dulu!

Mengapa ini disebut short-circuit? Karena bash berhenti mengevaluasi begitu hasilnya sudah pasti. Pada A && B, jika A gagal, bash tidak perlu menjalankan B (hasil sudah pasti salah). Pada A || B, jika A sukses, B dilewati (hasil sudah pasti benar). Inilah mengapa idiom ini efisien — dan kenapa urutan operan sangat menentukan.

Kapan && / || dan Kapan if?

Kedua gaya ini bisa menulis ulang satu sama lain, tapi punya konteks terbaiknya:

Gaya ringkas vs gaya eksplisit
#!/usr/bin/env bash
# Ringkas — untuk aksi satu baris: "kalau berhasil, lakukan ini"
systemctl start nginx && echo "nginx berjalan"
 
# Eksplisit — untuk logika bercabang yang butuh penjelasan
if systemctl start nginx; then
    echo "nginx berjalan"
else
    echo "Gagal memulai nginx" >&2
    exit 1
fi

Aturan praktisnya: &&/|| untuk aksi beruntun yang pendek dan jelas; if untuk logika yang bercabang, ber-komentar, atau berperilaku berbeda saat gagal. Skrip produksi lebih sering butuh if — karena saat kegagalan terjadi, kita hampir selalu perlu melakukan lebih dari sekadar mencetak satu baris (misalnya exit 1 dan log). Namun ada satu pengecualian wajib yang harus selalu diingat — lihat pitfall nomor 4 di bawah.

Praktik: Skrip Monitoring Disk Space & File

Saatnya merangkai semua operator test menjadi skrip monitoring yang realistis — gabungan dari episode 5 (argumen), episode 8 (aritmatika), dan episode ini (pengkondisian):

cek_disk.sh — monitoring ambang batas + cek file
#!/usr/bin/env bash
set -euo pipefail
 
threshold="${1:-80}"
log_file="/var/log/cek_disk.log"
 
if ! [[ "$threshold" =~ ^[0-9]+$ ]]; then
    echo "Error: ambang batas harus angka." >&2
    exit 1
fi
 
pemakaian=$(df --output=pcent / | tail -1 | tr -d ' %')
 
if [[ -f "$log_file" ]]; then
    if [[ -w "$log_file" ]]; then
        echo "[$(date +%F)] pemakaian=$pemakaian%" >> "$log_file"
    else
        echo "PERINGATAN: $log_file tidak bisa ditulis." >&2
    fi
fi
 
if (( pemakaian >= threshold )); then
    echo "KRITIS: pemakaian disk ${pemakaian}% melebihi ambang ${threshold}%."
    exit 2
else
    echo "OK: pemakaian disk ${pemakaian}% di bawah ambang ${threshold}%."
    exit 0
fi
Skrip monitoring yang menggabungkan test string, angka, dan file
Menjalankan
./cek_disk.sh 90
Contoh output
OK: pemakaian disk 37% di bawah ambang 90%.

Mari bedah bagaimana setiap jenis test berkontribusi:

BarisTest yang DipakaiTujuan
${1:-80}Parameter expansion dengan defaultSkrip jalan tanpa argumen, ambang default 80
[[ "$threshold" =~ ^[0-9]+$ ]]String regex dengan ! (negasi)Menolak ambang yang bukan angka murni
[[ -f "$log_file" ]]File: apakah file log adaJangan meng-appended ke file yang belum ada
[[ -w "$log_file" ]]File: apakah bisa ditulisPeringatkan alih-alih gagal diam-diam
(( pemakaian >= threshold ))Angka dengan (( ))Keputusan utama: melewati ambang atau tidak

Perhatikan bagaimana ketiga jenis test (string, file, angka) bekerja berdampingan untuk satu tujuan. Skrip ini bisa dipasang di cron untuk berjalan tiap 5 menit — dan karena exit 0/exit 2 digunakan, penelepon (misalnya sistem monitoring) bisa membedakan "semua baik" dari "ada masalah" hanya dari exit status. Inilah kekuatan pengkondisian yang dirancang dengan kesadaran penuh.

Common Pitfalls: Jebakan Pengkondisian

1. Spasi di dalam [ ] hilang

[ "$a" = "b" ] benar; [ "$a" = "b"] error "missing ]"; [ "$a"="b" ] error "unary operator expected". Karena [ adalah perintah, setiap token harus dipisah spasi. Ini bukan sekadar gaya — ini sintaks.

2. Memakai > / < sebagai perbandingan angka

Di dalam [ ] dan [[ ]], > dan < adalah perbandingan string (urutan abjad), bukan angka! [[ "9" > "10" ]] bernilai benar karena "9" secara leksikografis lebih besar dari "1". Untuk angka, gunakan -gt, -lt, dst. (atau (( ))).

3. Lupa mengutip variabel di dalam [ ]

[ $var == "x" ] dengan $var kosong menjadi [ == "x" ] → error "unary operator expected". Di [ ], kutip selalu. Di [[ ]], kutip menjadi opsional (tapi tetap disarankan).

4. cmd1 && cmd2 || cmd3 — pola tiga arah yang bahaya

Ini pola yang menggoda tapi berbahaya: jika cmd2 sendiri gagal, bash akan menjalankan cmd3 juga — karena cmd1 && cmd2 menghasilkan "salah" saat cmd2 gagal, lalu || cmd3 ikut tereksekusi. Hasilnya, jalur "sukses" bisa tetap memicu cabang error. Jangan menulis logika tiga arah dengan &&/|| — gunakan if/else yang tidak ambigu.

5. [ $var == "x" ] vs [[ $var == "x" ]] — perbedaan nyata

Selain masalah kutip, ada jebakan halus lain: dalam [[ ]], == dan = sama-sama perbandingan string. Dalam [ ] POSIX, operator yang resmi adalah === mungkin bekerja di bash, tapi di sh/dash perilakunya tidak dijamin. Jika skrip harus portable, tulis [ "$var" = "x" ]. Jika bash-only, gunakan [[ ]].

6. Lupa ; atau then di baris yang sama

if [ ... ] then — tanpa ; sebelum then — error. Dua gaya valid: if [ ... ]; then (satu baris) atau if [ ... ] lalu baris baru then. Pilih satu dan konsisten.

Penutup

Pada episode 9 ini, kita telah melengkapi fondasi pengambilan keputusan: struktur if/elif/else/fi yang bekerja berbasis exit status perintah; perbedaan fundamental [ ] (perintah POSIX yang rapuh terhadap word splitting) vs [[ ]] (keyword bash yang lebih aman, mendukung regex dan operator logika); katalog test operator untuk string (-z, -n, ==, !=), angka (-eq, -ne, -gt, -ge, -lt, -le), dan file (-f, -d, -e, -r, -w, -x, -s); serta short-circuit &&/|| — lengkap dengan skrip monitoring disk yang memadukan semuanya.

Inti yang harus dibawa pulang:

  • if membaca exit status, bukan boolean — kondisi adalah perintah.
  • Gunakan [[ ]] untuk skrip bash: lebih aman, regex, &&/|| di dalam.
  • String: -z -n == !=; Angka: -eq -ne -gt -ge -lt -le; File: -f -d -e -r -w -x -s.
  • Jangan pakai >/< untuk angka — itu perbandingan string.
  • Kutip variabel di dalam [ ]; hindari pola &&/|| tiga arah.

Kalian kini memiliki empat fondasi inti bash: data (argumen & input), daftar file (globbing), perhitungan (aritmatika), dan keputusan (pengkondisian). Kombinasinya sudah bisa membangun skrip otomasi yang nyata. Langkah berikutnya adalah memperhalus pengambilan keputusan itu sendiri. Di episode 10 selanjutnya, kita akan membahas Pengkondisian Lanjutan (Case Statement & Regex) — mencocokkan satu variabel terhadap banyak pola sekaligus dengan case ... esac, serta memvalidasi input seperti email, IP address, dan angka menggunakan regular expression dengan operator =~. Sampai jumpa di episode berikutnya!

Belajar BASH Scripting - Pengkondisian (Conditionals) & Test Operators | Belajar BASH Scripting