Belajar BASH Scripting - Perulangan (Loops) Bagian 1: for
Episode 11 of 27

Belajar BASH Scripting - Perulangan (Loops) Bagian 1: for

Mengotomatisasi pekerjaan berulang dengan perulangan `for`: dari bentuk daftar kata, rentang `{1..10}` dengan langkah `{1..10..2}`, hingga C-style `for ((i=0; i<10; i++))`. Lengkap dengan `break`, `continue`, iterasi file via glob, dan praktik mass rename beserta jebakan yang sering menjebak.

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

Pendahuluan

Setelah di episode 10 sebelumnya kita membahas pengkondisian lanjutancase ... esac untuk mencocokkan banyak pola sekaligus dan operator =~ untuk validasi regex — pada episode kali ini kita membuka topik yang sama fundamentalnya: perulangan (loops). Kalau pengkondisian membuat script kalian bisa berpikir, perulangan membuat script kalian bisa bekerja.

Bayangkan kalian ditugaskan mengganti ekstensi dari 500 file .txt menjadi .md satu per satu. Secara manual, itu berjam-jam kerja yang membosankan dan rawan salah. Dengan perulangan, itu sepuluh baris script yang selesai dalam sepersekian detik. Inilah bedanya manusia dan mesin: mesin tidak bosan mengulang hal yang sama. Perulangan adalah cara kalian memerintahkan mesin untuk memanfaatkan keunggulan itu.

Pada episode kali ini kita fokus pada for — perulangan paling sering dipakai di Bash. Kita akan membedah tiga bentuknya: bentuk daftar kata, bentuk rentang angka, dan bentuk gaya-C. Kita tutup dengan break, continue, serta praktik nyata mass rename file. Episode berikutnya akan menyusul dengan while, until, dan membaca file baris demi baris.

Pembahasan Utama

Mengapa Perulangan Itu Kekuatan Utama Scripting?

Sebelum membedah sintaks, penting untuk memahami mengapa perulangan menjadi alasan utama orang menulis script di tempat pertama. Perulangan mengubah pekerjaan linier menjadi pekerjaan eksponensial: satu perintah yang kalian tulis sekali bisa berdampak ke puluhan, ratusan, bahkan ribuan item.

Coba bandingkan dua pendekatan ini. Untuk menghapus file backup basi:

Tanpa perulangan vs dengan perulangan
rm backup-2024-01-01.tar.gz
rm backup-2024-01-02.tar.gz
rm backup-2024-01-03.tar.gz
for f in backup-*.tar.gz; do
    rm "$f"
done

Baris diff di atas menangkap esensi automation: daripada menulis satu perintah per file, kalian menulis satu perintah untuk semua file. Ketika besok ada file ke-31, pendekatan pertama butuh kode baru; pendekatan kedua bekerja tanpa perubahan. Perulangan adalah cara berpikir data-driven: script tidak lagi peduli berapa banyak item, yang penting polanya.

Bentuk Pertama: for item in a b c (Daftar Kata)

Bentuk paling dasar dari for adalah mengulang atas daftar kata yang dipisahkan spasi:

For sederhana atas daftar kata
for kota in Jakarta Bandung Surabaya; do
    echo "Kota: $kota"
done
Variabel item berganti nilai di setiap iterasi

Bacaan baris ini: "untuk setiap kota di dalam daftar Jakarta Bandung Surabaya, lakukan blok do...done." Pada iterasi pertama kota berisi Jakarta, lalu Bandung, lalu Surabaya, dan perulangan selesai. Analogikan dengan sabuk konveyor pabrik: daftar kata adalah kotak-kotak yang lewat, dan blok do...done adalah stasiun kerja yang memproses satu kotak setiap kali.

Variabel kota adalah loop variable — ia hidup selama perulangan dan berubah setiap iterasi. Kalian bebas menamainya apa saja: file, i, user, server, dan sebagainya. Yang penting konsisten di dalam blok.

Daftar kata juga bisa berasal dari hasil ekspansi variabel:

For atas daftar dari variabel
server_list="web-01 web-02 db-01"
for server in $server_list; do
    echo "Menyiapkan deploy ke $server"
done
Setiap elemen variabel menjadi satu iterasi

Bentuk Kedua: Rentang {1..10} dan {1..10..2}

Menulis for i in 1 2 3 4 5 6 7 8 9 10 itu membosankan dan rawan typo. Bash menyediakan brace expansion untuk menghasilkan deret angka secara otomatis:

Rentang angka dengan brace expansion
for i in {1..10}; do
    echo "Iterasi ke-$i"
done
 
for genap in {0..10..2}; do
    echo "Angka genap: $genap"
done
{1..10} dan {1..10..2} menghasilkan deret

{1..10} menghasilkan 1 2 3 4 5 6 7 8 9 10, dan {0..10..2} menghasilkan 0 2 4 6 8 10 — angka awal, angka akhir, dan langkah (step). Sintaks {start..end..step} adalah versi Bash modern; pastikan Bash kalian versi 4 atau lebih untuk dukungan penuh.

Brace expansion tidak hanya untuk angka. Kalian bisa menghasilkan deret huruf, atau kombinasi yang lebih kreatif:

Rentang huruf dan pola kombinasi
for huruf in {a..f}; do
    echo "Huruf: $huruf"
done
{a..z} menghasilkan deret huruf

Tip

Brace expansion terjadi sebelum loop dijalankan, bukan saat iterasi. Artinya {1..1000000} di sisi kanan akan membuat daftar satu juta kata di memori lebih dulu. Untuk perulangan sangat besar, lebih efisien memakai bentuk C-style (dibahas sebentar lagi) yang tidak membutuhkan daftar material di awal.

Bentuk Ketiga: C-Style for ((i=0; i<10; i++))

Bentuk ketiga meniru sintaks bahasa C dan sangat berguna saat kalian butuh kontrol numerik yang presisi — indeks, penghitung, atau deret dengan kondisi berhenti yang dinamis:

C-style for loop
for ((i=0; i<10; i++)); do
    echo "Hitungan ke-$i"
done
Tiga bagian: inisialisasi, kondisi, increment

Struktur for (( ... )) memiliki tiga ruas yang dipisahkan ;:

RuasContohFungsi
Inisialisasii=0Dijalankan sekali di awal, menyiapkan nilai awal
Kondisii<10Dievaluasi sebelum tiap iterasi; loop berhenti jika salah
Incrementi++Dijalankan setelah tiap iterasi, memperbarui penghitung

Perhatikan bahwa variabel i di sini tidak memakai $ pada ruas inisialisasi dan increment — penulisan $i=0 justru salah. Ini salah satu kebiasaan yang perlu kalian pindah dari bahasa pemrograman lain: di dalam (( )), nama variabel ditulis tanpa $.

Bentuk C-style adalah pilihan tepat ketika jumlah iterasi dihitung — misalnya mencoba koneksi 5 kali sebelum menyerah:

Retry dengan C-style loop
for ((attempt=1; attempt<=5; attempt++)); do
    echo "Percobaan ke-$attempt..."
    if ping -c 1 server-db >/dev/null 2>&1; then
        echo "Koneksi berhasil!"
        break
    fi
    sleep 2
done
Coba sampai 5 kali lalu menyerah

break dan continue: Mengendalikan Alur Perulangan

Kadang kalian tidak ingin menjalankan semua iterasi. Dua kata kunci ini memberi kalian kendali seperti rem dan gas pada perulangan:

  • break — menghentikan perulangan seketika, melompat keluar dari do...done tanpa menunggu iterasi selesai.
  • continue — melewati iterasi saat ini saja dan langsung melompat ke item berikutnya.

Contoh penggunaan continue untuk melewati file yang bukan target, dan break untuk berhenti total:

continue dan break dalam aksi
for file in *.log; do
    if [[ "$file" != app-* ]]; then
        continue
    fi
    echo "Memproses $file"
done
 
for i in {1..10}; do
    if (( i > 5 )); then
        break
    fi
    echo "Masih di angka $i"
done
continue melewati satu iterasi, break menghentikan seluruh loop

Note

Gunakan continue untuk filter dan break untuk early exit. Membaca kode yang penuh if...else di dalam loop akan cepat melelahkan; continue memindahkan logika pengecualian ke baris awal sehingga alur utama tetap mudah dibaca. Ingat pola ini: periksa, lalu continue, lalu kerjakan — sangat efektif di script panjang.

Iterasi File dengan Glob

Salah satu penggunaan for yang paling sering di dunia nyata adalah mengiterasi file di sebuah direktori. Kuncinya: biarkan glob expansion yang menghasilkan daftar file, lalu bungkus variabel dengan tanda kutip saat menggunakannya:

Iterasi semua file .jpg
for foto in *.jpg; do
    echo "Memproses $foto"
    # misal: resize, konversi, atau rename
done
Glob menghasilkan daftar file; pastikan variabel di-quote

Bentuk for foto in *.jpg membuat Bash memperluas *.jpg menjadi daftar file yang cocok — dan yang penting, daftar ini sudah menjadi item terpisah, bukan satu string panjang. Ini berbeda dari for foto in $(ls *.jpg) yang rawan masalah kata yang mengandung spasi.

Perhatikan juga kasus ekstrem: jika tidak ada file .jpg, glob tanpa nullglob akan tetap menghasilkan string literal *.jpg dan loop menjalankan satu iterasi dengan $foto = *.jpg. Untuk mencegahnya, aktifkan opsi nullglob:

Menghindari iterasi glob kosong
shopt -s nullglob
for foto in *.jpg; do
    echo "Memproses $foto"
done
nullglob membuat glob kosong menghasilkan daftar kosong

Praktik: Mass Rename File

Mari kita rangkai semuanya dalam satu studi kasus nyata yang sangat sering dibutuhkan admin: mass rename. Misalkan kalian memiliki sekumpulan file log dengan ekstensi lama .log yang harus diubah menjadi .txt:

Mass rename file log
#!/usr/bin/env bash
shopt -s nullglob
 
for file in *.log; do
    baru="${file%.log}.txt"
    mv "$file" "$baru"
    echo "Renamed: $file -> $baru"
done
Quoting variabel mencegah nama file berspasi terpecah

Mari bedah baris kuncinya: "${file%.log}.txt" memakai parameter expansion untuk menghapus akhiran .log dari nama file (% memotong dari belakang), lalu menyisipkan .txt. Teknik mv "$file" "$baru" dengan kedua argumen ter-quote adalah golden rule untuk semua operasi file: selalu quote variabel yang berisi nama file, karena nama file di Linux boleh mengandung spasi, tanda kurung, bahkan newline.

Caution

Selalu uji script mass rename pada salinan data dulu. Satu typo di pola pemotongan nama bisa berujung pada puluhan file tertimpa atau hilang tanpa jejak. Kebiasaan yang sehat: jalankan versi dry-run (misal hanya echo "$file -> $baru") sebelum versi sungguhan yang berisi mv. Di produksi, mv juga bisa diperkuat dengan opsi -n (no-clobber) agar tidak menimpa file yang sudah ada.

Kesalahan Umum dalam Perulangan for

KesalahanGejalaSolusi
for file in $list tanpa kutip pada penggunaanFile berspasi terpecah jadi dua itemSelalu "$file" saat memakai variabel
for i in $(command) alih-alih array/globOutput terpecah berdasarkan spasi & globPakai array (mapfile) atau glob literal
Lupa (( )) di C-style, menulis for (i=0; ...)Error syntax error near unexpected token '('Tulis for (( ... )) dengan kurung ganda
Ruas increment i++ memakai $i++Nilai tidak pernah bertambah benar / warningTulis i++ tanpa $ di dalam (( ))
Glob tanpa nullglob saat tidak ada fileLoop berjalan sekali dengan literal *.jpgshopt -s nullglob sebelum loop

Satu kesalahan yang paling sering membuat pemula bingung adalah perulangan atas output command substitution:

Pola yang keliru: word splitting di $(...)
for i in $(ls *.txt); do
    echo "$i"
done
Output dengan spasi atau glob karakter akan terpecah tak terkendali

Baris $(ls *.txt) menjalankan ls, lalu hasilnya dipecah berdasarkan spasi (word splitting) dan karakter glob ikut diekspansi. Akibatnya: file bernama catatan penting.txt berubah menjadi dua iterasi (catatan dan penting.txt), dan file bernama dokumen[1].txt bisa berubah maknanya. Solusinya, seperti kita bahas, adalah glob literal (for i in *.txt) atau array:

Pola yang benar: glob atau array
for i in *.txt; do
    echo "$i"
done
 
mapfile -t files < <(find . -name "*.txt")
for i in "${files[@]}"; do
    echo "$i"
done
Glob langsung, atau mapfile untuk output multi-baris

Warning

Kesalahan terburuk dari semuanya: infinite loop pada C-style for ((i=0; i<10; i++)) ketika ruas increment tertulis keliru, misalnya i-1 alih-alih i+1 — nilai i tidak pernah bertambah sehingga kondisi i<10 selalu benar. Selalu periksa bahwa ruas increment benar-benar menggerakkan penghitung mendekati kondisi berhenti. Sebagai jaring pengaman, jalankan script dengan timeout 5 ./script.sh saat sedang menulis loop baru.

Penutup

Pada episode 11 ini kita telah menguasai perulangan for dalam tiga bentuknya: daftar kata (for item in a b c), rentang brace expansion ({1..10} dan {1..10..2}), dan gaya-C (for ((i=0; i<10; i++))). Kita juga mempelajari break untuk menghentikan perulangan seketika, continue untuk melewati satu iterasi, iterasi file via glob dengan nullglob, dan praktik mass rename yang menjadi salah satu penggunaan paling umum di dunia nyata. Yang tak kalah penting, kita mencatat jebakan klasik: unquoted variable, word splitting pada $(...), dan glob kosong.

Prinsip yang harus kalian bawa pulang: glorifikasi perulangan adalah keberanian menulis satu perintah untuk ribuan item. Dari mana pun daftar itemnya — daftar kata, rentang angka, hasil glob, atau output perintah — kuncinya selalu sama: biarkan Bash yang memecah daftar menjadi item, dan quote setiap variabel saat digunakan.

Namun for bukan satu-satunya perulangan di Bash. Ada situasi di mana kalian tidak tahu sebelumnya berapa kali harus mengulang — misalnya membaca file yang panjangnya tidak diketahui, atau menunggu suatu kondisi terpenuhi. Untuk itu, Bash menyediakan while dan until. Di episode 12 selanjutnya kita akan membahas perulangan bagian 2: while, until, dan membaca file baris demi baris — lengkap dengan pengolahan CSV dan jebakan subshell yang kerap membuat variabel "hilang" misterius. Sampai jumpa di episode berikutnya!

Belajar BASH Scripting - Perulangan (Loops) Bagian 1: for | Belajar BASH Scripting