Melanjutkan perulangan dengan `while` yang berjalan selama kondisi benar, `until` yang berjalan sampai kondisi terpenuhi, dan pola `while true` untuk daemon. Dibahas pula membaca file baris demi baris dengan `while read -r line`, pengolahan CSV, serta jebakan subshell yang membuat variabel "hilang" setelah pipeline.

Setelah di episode 11 sebelumnya kita menguasai perulangan for — dari daftar kata, rentang {1..10}, hingga C-style for ((i=0; i<10; i++)) — pada episode kali ini kita melengkapi gudang perulangan dengan pasangannya: while dan until.
for itu seperti tukang sortir di pabrik yang tahu persis berapa kotak akan lewat: ia butuh daftar lengkap sebelum mulai. Tapi ada banyak pekerjaan yang tidak tahu berapa kali harus diulang sebelum selesai — menunggu service hidup, membaca file yang barisnya bisa bertambah, atau menunggu pengguna mengetik jawaban yang benar. Untuk pekerjaan seperti ini, while dan until adalah alat yang tepat: mereka mengulang selama sebuah kondisi terpenuhi, bukan selama ada item tersisa.
Bonus terbesar episode ini: membaca file baris demi baris dengan while read. Hampir semua script operasional — parser log, pengolahan file konfigurasi, pemrosesan CSV — bertumpu pada pola ini. Kita juga akan membedah salah satu misteri paling terkenal di Bash: mengapa variabel di dalam while sering "hilang" setelah pipeline selesai (jawabannya: subshell). Mari mulai.
while: Mengulang Selama Kondisi Benarwhile adalah perulangan yang paling fleksibel. Ia mengevaluasi sebuah kondisi — perintah atau test apa pun — dan selama kondisi itu mengembalikan exit status 0 (sukses), blok do...done terus dijalankan:
count=0
while [ "$count" -lt 5 ]; do
echo "Hitungan: $count"
count=$((count + 1))
doneBacaan kode di atas: "selama $count kurang dari 5, cetak nilainya lalu tambah 1." Tanpa baris count=$((count + 1)), kondisi tidak akan pernah berubah dan kalian terjebak infinite loop. Ini kesalahan klasik — kondisi dan perubahan kondisi adalah dua hal yang harus selalu ada bersama dalam perulangan berbasis kondisi.
Analogikan while dengan tungku penjaga di kamp: api dibiarkan menyala selama kayu masih ada ([ -n "$kayu" ]). Setiap iterasi kalian memeriksa kayu, dan ketika habis, api padam. Bash sendiri yang mengevaluasi kondisi di awal setiap iterasi — sebelum blok dieksekusi.
until: Mengulang Sampai Kondisi Benaruntil adalah kebalikan logis dari while — ini bukan sekadar kosmetik, melainkan perbedaan cara berpikir:
while [ kondisi ] → jalankan selama kondisi benar.until [ kondisi ] → jalankan sampai kondisi benar (berhenti begitu benar).count=0
until [ "$count" -ge 5 ]; do
echo "Masih di angka $count"
count=$((count + 1))
doneSecara hasil, contoh di atas identik dengan versi while. Perbedaannya pada keterbacaan: pilih until ketika kondisi berhenti lebih natural untuk diucapkan daripada kondisi lanjut. Bayangkan menunggu pengguna menjawab "ya":
jawaban=""
until [ "$jawaban" = "ya" ]; do
read -p "Konfirmasi (ketik 'ya'): " jawaban
done
echo "Dikonfirmasi!"Bacaan mentalnya: "tanyai terus sampai dia menjawab ya." Jauh lebih mudah dibaca daripada while [ "$jawaban" != "ya" ] yang memaksa kalian berpikir dalam negasi.
while true + break: Daemon RinganAda satu pola yang sangat populer di script daemon dan watcher: while true — perulangan yang tidak pernah berhenti secara alami, dan dihentikan secara eksplisit lewat break dari dalam. Pola ini cocok ketika kondisi berhenti sulit ditulis di bagian atas loop (misalnya tergantung hasil kerja iterasi):
while true; do
if [ -f /tmp/stop-dengan-fresh ]; then
echo "File penanda terdeteksi, berhenti."
break
fi
echo "Menjalankan tugas rutin... (Ctrl+C untuk berhenti)"
sleep 10
donePerintah true adalah perintah bawaan Bash yang selalu mengembalikan exit status 0 — kondisi yang tak pernah salah, sehingga loop tak pernah berhenti oleh kondisinya sendiri. Di dalamnya, break menjadi satu-satunya jalan keluar yang disengaja. Pola ini juga sering menampung continue untuk melompati satu siklus:
while true; do
read -p "Perintah: " cmd
case "$cmd" in
next) continue ;;
quit) break ;;
*) echo "Eksekusi: $cmd" ;;
esac
done
echo "Selesai."Note
Kombinasi case (episode 10) + while true + break membentuk inti dari hampir semua interactive REPL dan menu loop di script Bash. Pola ini juga dasar dari script watchdog yang memantau proses dan me-restart-nya bila mati. Hafalkan polanya: while true untuk siklus abadi, case untuk menerjemahkan input, continue/break untuk kendali keluar.
Sekarang kita masuk ke pola paling penting di episode ini. Untuk memproses sebuah file baris demi baris, formula standarnya adalah:
while read -r line; do
echo "Baris: $line"
done < file.txtMari bedah setiap bagiannya:
while read -r line — setiap iterasi, perintah read mengambil satu baris dari stdin dan menyimpannya ke variabel line, lalu mengembalikan exit status 0 (berhasil membaca). Ketika file habis, read mengembalikan status non-0 dan loop berhenti. Keindahan pola ini: loop tahu berhenti sendiri, tanpa menghitung baris.done < file.txt — redirection input menempel di done, bukan di awal. Ini memberitahu: "pasok setiap baris file.txt sebagai stdin untuk perintah read di dalam loop."Faktanya, read adalah kunci di sini — setiap iterasi ia melahap satu baris dan menggeser kursor ke baris berikutnya. Ini seperti ban berjalan tempat kalian mengambil satu lembar dokumen setiap kali sampai tumpukan habis.
read -r?Opsi -r pada read mungkin tampak sepele, tetapi ia menyelamatkan kalian dari bug yang sangat halus. Tanpa -r, read memperlakukan backslash (\) sebagai escape character — karakter yang memodifikasi karakter berikutnya:
echo 'C:\data\server\logs.txt' > path.txt
read path < path.txt
echo "Tanpa -r : $path"
# Tanpa -r : C:dataserverlogs.txt <- backslash hilang!
read -r path < path.txt
echo "Dengan -r: $path"
# Dengan -r: C:\data\server\logs.txtMengapa read tanpa -r menghilangkan backslash? Karena read dirancang untuk mendukung line continuation — backslash di akhir baris berarti "sambung dengan baris berikutnya". Tanpa -r, backslash di tengah baris pun ikut dicerna. Untuk data dunia nyata — path Windows, regex, escape sequence — backslash adalah data yang sah dan harus dipertahankan. Aturan emasnya: selalu tulis read -r kecuali kalian punya alasan eksplisit untuk tidak melakukannya.
Ada jebakan kedua yang lebih samar: read secara default menghilangkan spasi dan tab di awal dan akhir baris. Ini karena IFS (Internal Field Separator) default berisi spasi, tab, dan newline. Untuk file yang barisnya sengaja memiliki spasi pembuka (misalnya kode sumber atau output yang diindentasi), gunakan IFS= sebelum read:
while IFS= read -r line; do
echo ">>> $line <<<"
done < indentasi.txtPerhatikan penulisannya: while IFS= read -r line — penugasan IFS= langsung di baris yang sama dengan read. Ini adalah penugasan variabel satu-perintah (command assignment), yang hanya berlaku untuk satu perintah tersebut. Dengan IFS kosong, read tidak memotong karakter spasi mana pun dari baris.
Important
Selalu pasangkan read dengan -r, dan gunakan IFS= bila baris-baris file mengandung spasi pembuka yang harus dipertahankan. Rumus lengkap yang aman untuk hampir semua file: while IFS= read -r line; do ...; done < file. Ketiga elemen — IFS=, read -r, dan done < file — adalah paket yang tidak bisa dicicil: mengurangi salah satunya berarti menunda bug aneh yang hanya muncul pada data tertentu.
while IFS=',' read -r f1 f2Keunggulan read yang paling sering dipakai di dunia nyata adalah kemampuannya memecah satu baris menjadi beberapa field sekaligus. Cukup beri tahu read daftar variabel — ia membagi baris berdasarkan IFS dan mengisi masing-masing variabel:
while IFS=',' read -r nama umur kota; do
echo "Nama : $nama"
echo "Umur : $umur"
echo "Kota : $kota"
echo "---"
done < data.csvUntuk setiap baris seperti arman,30,jakarta, read memecahnya berdasarkan koma dan mengisi $nama=arman, $umur=30, $kota=jakarta. Jika sebuah baris memiliki field lebih sedikit dari jumlah variabel, sisanya kosong; jika lebih banyak, field terakhir menampung sisanya.
Contoh lebih dekat dengan dunia DevOps: file servers.csv berisi daftar server dan perannya, lalu script melakukan ping ke semuanya:
while IFS=',' read -r host role; do
if ping -c 1 -W 2 "$host" >/dev/null 2>&1; then
echo "OK : $host ($role)"
else
echo "FAIL : $host ($role)"
fi
done < servers.csvTip
Untuk CSV dengan baris kosong atau komentar (baris diawali #), tambahkan filter di awal blok: [[ -z "$host" || "$host" == \#* ]] && continue. Pola "periksa, lalu lanjutkan" ini memastikan loop tidak memproses data sampah. Dan ingat: read memecah berdasarkan karakter tunggal pada IFS — untuk delimiter multi-karakter (mis. ||), gunakan alat lain seperti awk -F'\|\|'.
Ini salah satu misteri Bash paling terkenal dan paling sering membuat admin menyerang tembok. Coba jalankan script berikut:
total=0
cat data.txt | while read -r baris; do
total=$((total + 1))
done
echo "Total baris: $total" # output: Total baris: 0 <- BUG!Kalian mengharapkan total berisi jumlah baris, tetapi outputnya 0. Mengapa? Karena setiap elemen di dalam pipeline (cat ... | while ...) berjalan di subshell — proses Bash turunan yang memiliki salinan variabel sendiri. Penugasan total=$((total + 1)) terjadi di subshell, dan ketika subshell selesai, semua perubahannya dibuang. $total di shell induk tidak pernah tersentuh.
Analoginya: kalian mengirim seorang kurir (subshell) membawa buku catatan (salinan variabel). Kurir mencatat angka, tapi buku yang dia bawa adalah fotokopi — begitu dia pergi, buku asli tetap kosong.
Ada beberapa solusi. Yang paling sederhana: jangan gunakan pipeline sama sekali — gunakan redirection langsung:
total=0
while read -r baris; do
total=$((total + 1))
done < data.txt
echo "Total baris: $total"Solusi alternatif untuk kasus tertentu — jika kalian benar-benar butuh pipeline (misalnya karena ada proses lain yang menyaring data), pakai process substitution atau pindahkan hasil ke variabel dengan mapfile:
total=0
while read -r baris; do
total=$((total + 1))
done < <(grep -v '^#' data.txt)
echo "Total: $total"
mapfile -t baris_baris < data.txt
echo "Jumlah baris: ${#baris_baris[@]}"Warning
Prinsip yang harus diingat: setiap perintah di dalam pipeline a | b | c berjalan di subshell, dan semua variabel yang diubah di dalamnya tidak akan terlihat setelah pipeline selesai. Ini berlaku tidak hanya untuk while — berlaku juga untuk perulangan lain yang dihubungkan ke pipeline. Kalau sebuah variabel "tidak mau berubah" di script kalian, curigai pipeline sebagai penyebabnya terlebih dahulu. Aturan praktis: gunakan done < file (redirection) atau while ... done < <(command) (process substitution), bukan pipeline.
while, until, dan Membaca File| Kesalahan | Gejala | Solusi |
|---|---|---|
| Lupa memperbarui kondisi di dalam loop | Infinite loop | Pastikan ada perintah yang mengubah kondisi tiap iterasi |
| `while ... done | command` (pipeline) | Variabel hilang setelah loop |
read line tanpa -r | Backslash di data hilang/dicerna | Selalu read -r line |
Lupa done < file | Loop tidak membaca file, read menunggu stdin | Tempel redirection di done |
while read dengan baris berspasi pembuka | Spasi awal terpotong | while IFS= read -r line |
Mengetik while tanpa ; do atau do terpisah | syntax error near unexpected token | Format: while [ kondisi ]; do ... done |
Caution
Infinite loop adalah musuh paling berbahaya di episode ini. Di terminal, Ctrl+C menghentikannya — tetapi di script yang berjalan non-interaktif (cron, CI), tidak ada tombol itu. Kebiasaan yang menyelamatkan nyawa: selalu beri batas pada loop yang melibatkan kondisi eksternal, misalnya counter maksimum percobaan: for ((attempt=0; attempt<10; attempt++)); do [ kondisi ] && break; sleep 5; done. Dan saat menguji script baru, jalankan dengan timeout 10 ./script.sh sebagai jaring pengaman.
Pada episode 12 ini kita telah melengkapi perulangan Bash dengan while (berjalan selama kondisi benar), until (berjalan sampai kondisi benar), dan pola while true + break untuk daemon dan REPL. Yang lebih penting, kita menguasai pola paling produktif dalam scripting Bash: while IFS= read -r line; do ...; done < file untuk membaca file baris demi baris, memecah CSV menjadi field dengan IFS=',', dan mengungkap misteri subshell — mengapa variabel yang diubah dalam pipeline "menghilang" dan bagaimana menghindarinya.
Prinsip yang harus kalian bawa pulang: for untuk daftar yang diketahui, while/until untuk kondisi yang dievaluasi, dan selalu read -r (plus IFS= bila perlu) saat menyentuh data dari file. Dengan kombinasi pengkondisian dan perulangan, script kalian kini bisa membaca, menilai, dan mengulang — tiga kemampuan inti automation.
Namun ada satu masalah yang mulai terasa: kode kalian semakin panjang, dan pola-pola yang sama (misalnya "baca file, filter, laporkan") mulai terulang di banyak tempat. Di episode 13 selanjutnya kita akan membahas solusinya: functions — cara membungkus logika menjadi blok yang bisa dipanggil ulang, lengkap dengan local variable, argumen, dan nilai balik. Di sanalah script kalian berubah dari sekadar menjalankan tugas menjadi arsitektur kode yang rapi. Sampai jumpa di episode berikutnya!