Menyimpan data pasangan key-value dengan associative array: deklarasi wajib `declare -A`, menambah dan membaca `dict[key]=val`, mengambil semua key `"${!dict[@]}"`, semua nilai, hingga penghitungan jumlah. Dilengkapi praktik mapping service-ke-port, konfigurasi key-value, frequency counter, perbandingan dengan indexed array, dan jebakan BASH di bawah versi 4.

Setelah di episode 14 sebelumnya kita menguasai indexed array — lemari arsip berlaci bernomor yang menyimpan banyak nilai dalam satu variabel — pada episode kali ini kita melengkapi koleksi data Bash dengan pasangannya yang lebih canggih: associative array, atau dictionary/peta key-value.
Kalau indexed array itu lemari arsip dengan laci bernomor, associative array itu kamus atau buku telepon: kalian tidak mencari entri berdasarkan nomor urut, melainkan berdasarkan nama atau label. dict["nginx"] memberi nilai yang terkait dengan "nginx" tanpa harus ingat bahwa nginx berada di slot ke-3. Alih-alih bertanya "siapa orang di halaman 5?", kalian bertanya "siapa yang bernama Arman?" — jauh lebih natural untuk data yang punya identitas.
Keunggulan ini sangat terasa di dunia DevOps: memetakan nama service ke port-nya, menyimpan konfigurasi key-value, atau menghitung frekuensi kemunculan kata dalam log. Associative array memungkinkan semua itu tanpa harus "mencari" nilai secara manual. Perhatikan satu syarat penting: associative array hanya tersedia di Bash 4.0 ke atas — dan di episode ini kita akan membedah mengapa deklarasi khusus declare -A wajib dilakukan. Mari mulai.
Pertama, mari kita rasakan masalah yang dipecahkan associative array. Misalkan kalian ingin memetakan nama service ke port default-nya. Dengan indexed array, kalian terpaksa menyimpan nama dan port di dua array terpisah dengan indeks yang harus selalu selaras:
service=("nginx" "mysql" "redis")
port=(80 3306 6379)
echo "Port mysql adalah ${port[1]}" # harus ingat: mysql di indeks 1Pendekatan ini rapuh: satu tambahan di tengah daftar membuat semua indeks berikutnya bergeser, dan kalian harus terus menerus "menerjemahkan" nama menjadi indeks. Associative array menghapus terjemahan itu sepenuhnya:
declare -A port
port[nginx]=80
port[mysql]=3306
port[redis]=6379
echo "Port mysql adalah ${port[mysql]}" # 3306Ini mengubah cara kalian berpikir: data tidak lagi disimpan berdasarkan posisi, melainkan berdasarkan identitas. Analogi yang paling pas: indexed array itu antrian nomor di loket, associative array itu buku telepon — kalian mencari nama, bukan nomor urut.
declare -AIni satu-satunya aturan yang paling sering dilanggar dan paling membingungkan. Associative array WAJIB dideklarasikan dengan declare -A sebelum dipakai:
declare -A port
port[nginx]=80Mengapa wajib? Karena perbedaan perilaku keduanya tidak bisa dideteksi otomatis. Tanpa declare -A, Bash menganggap setiap variabel sebagai indexed array (atau string) sampai diberi tahu lain. Akibatnya, penulisan:
port[nginx]=80
port[mysql]=3306
echo "${port[nginx]}" # 80 (kebetulan bekerja: 'nginx' dianggap 0)
echo "${port[mysql]}" # 3306 (kebetulan bekerja: 'mysql' juga 0)Mengapa kebetulan bekerja? Dalam konteks indeks array, key yang bukan angka dievaluasi sebagai ekspresi aritmetika: nginx dan mysql dianggap variabel kosong = 0, sehingga keduanya menimpa slot [0]. Hasilnya: port[nginx] dan port[mysql] sama-sama 3306 — data terakhir yang ditulis menang, dan data sebelumnya hilang. Ini bug yang diam-diam menghancurkan data tanpa error.
Warning
Jangan pernah lupa declare -A. Tanpa deklarasi ini, associative array kalian berubah menjadi indexed array yang diam-diam menimpa data: setiap key non-angka dievaluasi sebagai aritmetika (kebanyakan menjadi 0), sehingga banyak entri jatuh ke slot yang sama. Tidak ada pesan error — hanya data yang hilang. Aturannya sederhana: semua variabel associative array diawali declare -A nama di bagian atas script, tepat setelah #!/usr/bin/env bash.
Note
Associative array hanya didukung Bash 4.0 ke atas (dirilis 2009). Ini hampir pasti bukan masalah di distro modern, tetapi tetap perlu dicek saat bekerja di server tua atau container minimal: bash --version atau echo "${BASH_VERSINFO[0]}". Jika nilainya 3, ganti strategi — misalnya parsing key-value dengan loop while read dari sebuah file, atau beralih ke tool lain seperti awk.
Operasi dasar associative array sangat mirip dengan indexed array, dengan satu perbedaan: key-nya string, bukan angka:
declare -A config
config[nama]="Arman"
config[role]="DevOps Engineer"
config["nama aplikasi"]="inventory-app" # key boleh mengandung spasi
echo "Nama: ${config[nama]}"
echo "Role: ${config[role]}"
echo "App : ${config["nama aplikasi"]}"
echo "Jumlah key: ${#config[@]}" # 3Perhatikan detail menarik di baris config["nama aplikasi"]="inventory-app": key boleh mengandung spasi — dan inilah alasan utama mengapa key harus selalu dibungkus tanda kutip ganda saat diakses ("${config["nama aplikasi"]}"). Tanpa kutip, spasi di dalam key akan memecah ekspresi menjadi tidak valid.
Kemampuan yang sering dibutuhkan: mengiterasi semua key atau semua nilai. Ada dua notasi yang wajib dihafal:
"${!dict[@]}" — semua key (tanda ! berarti "daftar nama variabel/key"). Ingat notasi yang sama untuk parameter expansion ${!prefix*}."${dict[@]}" — semua nilai.declare -A port
port[nginx]=80
port[mysql]=3306
port[redis]=6379
echo "Semua key: ${!port[@]}"
# nginx mysql redis
for svc in "${!port[@]}"; do
echo "Service $svc di port ${port[$svc]}"
doneLoop for svc in "${!port[@]}" adalah pola paling penting untuk associative array: mengiterasi key, lalu menggunakannya untuk mengambil nilai. Dalam satu perulangan kalian mendapat dua informasi — kunci dan nilainya. Ini setara dengan for k, v in dict.items() pada Python, tapi dengan sintaks Bash yang khas.
Tip
Satu perbedaan kecil dengan indexed array: di associative array, "${!arr[@]}" (daftar key) tidak dijamin terurut seperti urutan penyisipan — pada beberapa versi Bash urutannya bisa berbeda. Jika urutan penting, gunakan printf '%s\n' "${!arr[@]}" | sort untuk mengurutkan key terlebih dahulu. Untuk sebagian besar penggunaan (mapping dan lookup), urutan jarang penting.
Mari praktikkan penggunaan yang paling umum: mapping nama service ke port-nya, lalu membuat laporan yang rapi:
#!/usr/bin/env bash
declare -A svc
svc[nginx]=80
svc[mysql]=3306
svc[redis]=6379
svc[postgresql]=5432
echo "Daftar service dan port:"
for name in "${!svc[@]}"; do
printf " %-12s -> %s\n" "$name" "${svc[$name]}"
donePerintah printf di sini memakai %-12s untuk meratakan nama service ke kiri selebar 12 karakter — outputnya rapi berkolom. Pola yang sama bisa dikembangkan: memeriksa apakah sebuah port sedang listening (ss -tln), atau mem-bandingkan port yang diharapkan dengan port nyata pada proses yang berjalan.
Skenario kedua: menyimpan konfigurasi aplikasi dalam associative array, lalu menggunakannya untuk menyusun command line atau laporan:
#!/usr/bin/env bash
declare -A cfg
cfg[host]="db-prod-01"
cfg[port]="5432"
cfg[user]="app_reader"
cfg[database]="inventory"
echo "Menghubungkan ke:"
echo " Host : ${cfg[host]}"
echo " Port : ${cfg[port]}"
echo " Database : ${cfg[database]}"
echo " User : ${cfg[user]}"
# Contoh pemakaian nyata: menyusun argumen koneksi
# psql -h "${cfg[host]}" -p "${cfg[port]}" -U "${cfg[user]}" "${cfg[database]}"Pola ini membuat konfigurasi terpusat di satu tempat — mengubah environment target (dari staging ke produksi) cukup mengubah satu blok deklarasi, tidak tersebar di banyak baris. Ini prinsip yang sama dengan config object pada aplikasi modern, hanya dengan sintaks Bash.
Kemampuan associative array yang paling kuat: menggunakan key sebagai penghitung. Karena setiap key unik, kalian bisa menghitung kemunculan setiap kata hanya dengan menambah nilai pada key tersebut. Tidak ada implementasi hash map manual — Bash sudah menyediakannya.
#!/usr/bin/env bash
declare -A freq
for kata in alpha beta alpha gamma beta alpha; do
freq["$kata"]=$(( ${freq["$kata"]:-0} + 1 ))
done
for k in "${!freq[@]}"; do
printf "%s : %d kali\n" "$k" "${freq[$k]}"
done
# alpha : 3 kali
# beta : 2 kali
# gamma : 1 kaliMari bedah baris intinya: freq["$kata"]=$(( ${freq["$kata"]:-0} + 1 )). Notasi ${freq["$kata"]:-0} adalah parameter expansion dengan default: jika key belum ada (nilainya kosong), gunakan 0. Lalu + 1 menaikkan hitungan, dan hasilnya disimpan kembali ke key yang sama. Baris inilah jantung frequency counter — dan bisa dipakai untuk menghitung kata dalam file log dengan menambahkan satu loop pembacaan:
declare -A freq
while IFS= read -r baris; do
for kata in $baris; do
freq["$kata"]=$(( ${freq["$kata"]:-0} + 1 ))
done
done < access.log
for k in "${!freq[@]}"; do
echo "$k ${freq[$k]}"
done | sort -k2 -rn | head -5Dengan tiga pola yang sudah dipelajari — while read (episode 12), for (episode 11), dan associative array — script ini berubah menjadi top-k word counter dari sebuah file log dalam 12 baris. Ini contoh bagaimana setiap episode saling membangun.
Berikut ringkasan yang bisa menjadi panduan keputusan:
| Aspek | Indexed Array | Associative Array |
|---|---|---|
| Key | Angka (0, 1, 2, ...) | String bebas (boleh spasi) |
| Deklarasi | Tidak wajib (default) | Wajib declare -A |
| Iterasi semua | "${arr[@]}" | "${!dict[@]}" untuk key |
| Jumlah elemen | ${#arr[@]} | ${#dict[@]} |
| Penggunaan pas | Daftar berurutan, antrian | Mapping/lookup berdasarkan nama |
| Butuh Bash | 2.0+ (dasar) | 4.0+ |
| Contoh dunia nyata | Daftar server, daftar file | Service→port, config, frequency counter |
| Kesalahan | Gejala | Solusi |
|---|---|---|
Lupa declare -A | Data menimpa diri sendiri (semua key jadi 0) | declare -A sebelum memakai |
| Key tanpa kutip ganda | Key berspasi gagal / terpecah | dict["nama aplikasi"], "${dict["nama aplikasi"]}" |
| Bash di bawah versi 4 | Error associative array / perilaku salah | Cek ${BASH_VERSINFO[0]}; ganti strategi |
"${dict[@]}" untuk mengambil key | Mendapat nilai, bukan key | Gunakan "${!dict[@]}" (dengan !) |
Menggunakan "${arr[*]}" pada iterasi | Semua nilai menyatu jadi satu string | Gunakan "${arr[@]}" |
| Mengharapkan urutan tertentu | Urutan iterasi key berbeda | Urutkan eksplisit bila perlu |
Caution
Kasus paling licin: script yang berfungsi normal di mesin kalian (Bash 5) tiba-tiba rusak di mesin lain (Bash 3). Associative array adalah fitur Bash 4+, dan kegagalannya bisa berupa error, atau lebih parah, perilaku diam-diam yang salah. Saat menulis script yang akan dijalankan di banyak host — termasuk container lama dan server RHEL tua — periksa versi Bash di lingkungan target, atau dokumentasikan syaratnya di awal script: if (( BASH_VERSINFO[0] < 4 )); then echo "Butuh Bash 4+" >&2; exit 1; fi.
Pada episode 15 ini kita telah menuntaskan perjalanan data Bash dengan associative array — kamus key-value yang menyimpan data berdasarkan identitas, bukan posisi. Kita membedah deklarasi wajib declare -A dan alasan di baliknya, operasi dasar (menambah, membaca, menghitung ${#dict[@]}), iterasi key dengan "${!dict[@]}" dan nilai dengan "${dict[@]}", lalu merangkainya dalam tiga praktik nyata: mapping service ke port, konfigurasi key-value, dan frequency counter untuk menghitung kemunculan kata. Kita juga membandingkannya dengan indexed array dan mencatat syarat keras Bash 4+.
Prinsip yang harus kalian bawa pulang: jika data kalian "punya nama", gunakan associative array — dan ingat tiga aturannya: declare -A wajib, key selalu di-quote, dan iterasi key lewat "${!dict[@]}". Dengan ini, toolkit data Bash kalian lengkap: string untuk satu nilai, indexed array untuk daftar berurutan, dan associative array untuk data beridentitas.
Dengan selesainya episode 15, kalian telah melewati setengah perjalanan seri ini: dari variabel, ekspansi, kondisional, perulangan, fungsi, hingga array. Kekuatan yang bisa kalian rangkai kini sangat besar — membangun script yang membaca data, mengambil keputusan, mengulang pemrosesan, membungkus logika dalam fungsi, dan menyimpan koleksi data dalam array. Di episode-episode berikutnya kita akan merangkai semuanya: penanganan error dan exit code, text processing dengan sed dan awk, hingga membangun tool command-line yang utuh dan siap produksi. Sampai jumpa di episode berikutnya!