Meneruskan Larik dan Peta Asosiatif antar Fungsi
Gunakan nameref dan ekspansi tidak langsung untuk meneruskan struktur data kompleks ke dalam dan ke luar fungsi dengan aman.
Meneruskan Larik dan Peta Asosiatif antar Fungsi adalah pelajaran Linux Command Line & Bash Scripting Mastery gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Linux Command Line & Bash Scripting Mastery, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Linux Command Line & Bash Scripting Mastery mencakup 4 pelajaran total.
Mengapa Meneruskan Larik ke Fungsi Itu Rumit
Dalam Bash, larik dan larik asosiatif bukan nilai kelas satu. Saat Anda mencoba meneruskan larik ke fungsi, Anda tidak dapat begitu saja menggunakan $my_array — itu hanya memperluas elemen pertama.
Perhatikan percobaan yang keliru berikut:
my_func "${my_array[@]}"Fungsi menerima daftar kata datar. Fungsi tersebut tidak dapat mengetahui di mana satu elemen berakhir dan elemen berikutnya dimulai, serta kehilangan seluruh struktur larik.
Bash menyediakan dua mekanisme yang andal untuk meneruskan struktur data kompleks:
- Referensi nama (
declare -n) — referensi ke variabel lain berdasarkan namanya (Bash 4.3+) - Perluasan tidak langsung (
${!varname[@]}) — mengakses variabel yang namanya disimpan dalam variabel lain (Bash versi lama)
Pelajaran ini membahas kedua teknik tersebut agar Anda dapat menulis fungsi yang tangguh dan dapat digunakan kembali untuk bekerja dengan larik dan peta.
Meneruskan Larik Berdasarkan Nama Menggunakan Referensi Nama
Pendekatan modern yang paling bersih adalah referensi nama: Anda meneruskan nama larik sebagai string, lalu di dalam fungsi mendeklarasikan variabel lokal yang merujuk ke larik tersebut.
Sintaks utama:
declare -n ref="$1"— kinirefadalah alias untuk nama variabel apa pun yang diteruskan sebagai argumen pertama- Anda membaca, melakukan iterasi, dan mengubah
refpersis seperti larik aslinya
Dengan cara ini, seluruh larik tidak perlu disalin dan fungsi dapat bekerja dengan larik berukuran apa pun.
#!/usr/bin/env bash
print_array() {
declare -n arr="$1" # nameref: arr -> caller's variable
echo "Array has ${#arr[@]} elements:"
for elem in "${arr[@]}"; do
echo " - $elem"
done
}
fruits=(apple banana cherry)
print_array fruitsMengubah Larik Pemanggil dari Dalam Fungsi
Karena referensi nama adalah alias yang sebenarnya, penulisan melalui referensi nama mengubah variabel asli milik pemanggil. Anda tidak perlu mengembalikan nilai dengan echo atau menggunakan variabel global.
Hal ini membuat referensi nama ideal untuk fungsi yang mengubah larik secara langsung — misalnya menormalkan string, menyaring elemen, atau mengurutkan.
#!/usr/bin/env bash
to_uppercase() {
declare -n _arr="$1"
for i in "${!_arr[@]}"; do
_arr[$i]="${_arr[$i]^^}" # ^^ = uppercase in Bash 4+
done
}
words=(hello world bash)
echo "Before: ${words[@]}"
to_uppercase words
echo "After: ${words[@]}"Mengembalikan Larik Baru Melalui Referensi Nama
Fungsi juga dapat menulis ke larik yang disediakan pemanggil dengan menerima namanya sebagai parameter keluaran. Pemanggil membuat larik kosong, meneruskan namanya, lalu fungsi mengisinya.
Pola ini menyerupai idiom klasik C yang meneruskan penunjuk ke penyangga hasil — hanya saja di sini semuanya dilakukan di dalam shell.
#!/usr/bin/env bash
get_even_numbers() {
local -a source=("$@")
# Last argument is the output array name — pop it off
local out_name="${source[-1]}"
unset 'source[-1]'
declare -n _out="$out_name"
_out=() # clear
for n in "${source[@]}"; do
(( n % 2 == 0 )) && _out+=("$n")
done
}
declare -a evens
get_even_numbers 1 2 3 4 5 6 7 8 evens
echo "Evens: ${evens[@]}"Jebakan Benturan Referensi Nama
Ada satu masalah penting pada referensi nama: jika variabel referensi nama lokal memiliki nama yang sama dengan variabel milik pemanggil, Bash memasuki putaran referensi diri tanpa akhir dan skrip gagal.
Misalnya, jika pemanggil menamai lariknya arr dan fungsi menjalankan declare -n arr="$1", referensi nama arr menunjuk ke dirinya sendiri.
Konvensi untuk menghindarinya: awali variabel referensi nama internal dengan garis bawah (misalnya, _arr, _ref, _out). Pemanggil hampir tidak pernah menggunakan nama seperti itu, sehingga benturan sangat jarang terjadi.
#!/usr/bin/env bash
# DANGER: caller uses variable named 'arr'
arr=(one two three)
bad_func() {
declare -n arr="$1" # collision! arr refers to itself
echo "${arr[@]}"
}
good_func() {
declare -n _arr="$1" # underscore prefix avoids collision
echo "${_arr[@]}"
}
# bad_func arr # would hang / error
good_func arrMeneruskan Larik Asosiatif (Peta) Berdasarkan Nama
Larik asosiatif (declare -A) bekerja dengan cara yang sama menggunakan referensi nama. Teruskan nama peta sebagai string dan deklarasikan referensi nama di dalam fungsi — Anda mendapatkan akses baca/tulis penuh ke semua pasangan kunci-nilai.
Hal ini sangat berguna untuk peta konfigurasi, pengurai opsi, dan tabel pencarian yang harus digunakan bersama oleh berbagai fungsi pustaka.
#!/usr/bin/env bash
print_map() {
declare -n _map="$1"
echo "Map contents:"
for key in "${!_map[@]}"; do
printf ' %-15s => %s\n' "$key" "${_map[$key]}"
done
}
declare -A config
config[host]="localhost"
config[port]="5432"
config[db]="myapp"
print_map configMenggabungkan Dua Peta dengan Referensi Nama
Karena referensi nama memberi fungsi alias yang selalu terhubung, Anda dapat menerapkan utilitas seperti penggabungan peta dengan rapi. Teruskan peta tujuan dan satu atau beberapa peta sumber berdasarkan nama; fungsi melakukan iterasi pada kunci sumber dan menuliskannya ke peta tujuan.
Referensi nama memungkinkan Anda menulis satu fungsi generik merge_map yang bekerja pada semua larik asosiatif dalam skrip Anda.
#!/usr/bin/env bash
merge_map() {
# merge_map dest src
declare -n _dest="$1"
declare -n _src="$2"
for key in "${!_src[@]}"; do
_dest["$key"]="${_src[$key]}"
done
}
declare -A defaults=([timeout]=30 [retries]=3 [verbose]=false)
declare -A overrides=([retries]=5 [log_level]=debug)
merge_map defaults overrides
for k in "${!defaults[@]}"; do
echo "$k = ${defaults[$k]}"
donePerluasan Tidak Langsung: Kompatibilitas dengan Bash Lama
Jika Anda harus mendukung Bash 4.0–4.2 (atau shell bawaan macOS versi lama), declare -n tidak tersedia. Alternatifnya adalah perluasan tidak langsung dengan ${!varname}.
Perluasan tidak langsung mengevaluasi nilai varname sebagai nama variabel dan mengembalikan nilai variabel tersebut. Untuk larik, Anda menggabungkannya dengan sintaks khusus untuk mendapatkan semua elemen.
Keterbatasan dibandingkan referensi nama:
- Pada praktiknya hanya dapat dibaca (penulisan kembali memerlukan
eval, yang membawa risiko injeksi) - Kunci larik asosiatif tidak dapat diiterasi dengan aman tanpa
eval - Gunakan referensi nama jika memungkinkan; gunakan perluasan tidak langsung hanya jika diperlukan
#!/usr/bin/env bash
sum_array() {
local arr_name="$1"
# Indirect: build a temporary copy by expanding arr_name[@]
local -a items
eval "items=( \"\${${arr_name}[@]}\" )"
local total=0
for n in "${items[@]}"; do
(( total += n ))
done
echo "$total"
}
numbers=(10 20 30 40)
result=$(sum_array numbers)
echo "Sum: $result"Membangun Pustaka Skrip Modular
Dalam proyek Bash profesional, fungsi utilitas disimpan dalam berkas pustaka (misalnya, lib/array_utils.sh) dan dimuat oleh skrip yang memerlukannya.
Polanya adalah:
- Setiap berkas pustaka hanya mendefinisikan fungsi — tanpa efek samping tingkat atas
- Cegah pemuatan ganda dengan variabel penanda:
[[ -n $__LIB_LOADED ]] && return; __LIB_LOADED=1 - Skrip pengguna menggunakan
sourceatau.untuk memuat pustaka - Fungsi bertukar data kompleks melalui referensi nama, sehingga seluruh logika tetap mandiri
Hasilnya adalah skrip yang dapat diuji, digunakan kembali, dan dipelihara — bukan trik shell sekali pakai.
Contoh Praktis: Pengurai Opsi yang Mengembalikan Peta
Contoh penggunaan di dunia nyata: pengurai opsi baris perintah yang mengisi larik asosiatif yang disediakan pemanggil. Pemanggil meneruskan nama larik sebagai argumen pertama, diikuti argumen "$@" yang sebenarnya.
Pola ini memungkinkan skrip apa pun menggunakan kembali pengurai yang sama tanpa menyalin kode atau bergantung pada variabel global.
#!/usr/bin/env bash
parse_opts() {
declare -n _opts="$1"
shift
while [[ $# -gt 0 ]]; do
case "$1" in
--host) _opts[host]="$2"; shift 2 ;;
--port) _opts[port]="$2"; shift 2 ;;
--user) _opts[user]="$2"; shift 2 ;;
*) echo "Unknown option: $1" >&2; shift ;;
esac
done
}
declare -A opts=([host]=localhost [port]=5432 [user]=admin)
parse_opts opts --host db.example.com --port 3306
echo "Connecting to ${opts[host]}:${opts[port]} as ${opts[user]}"Menggabungkan Referensi Nama Masukan dan Keluaran dalam Satu Fungsi
Fungsi dapat memiliki beberapa referensi nama secara bersamaan — satu untuk masukan dan satu untuk keluaran. Hal ini memungkinkan fungsi transformasi murni: fungsi membaca struktur sumber, menghitung hasil, lalu menuliskannya ke struktur tujuan, semuanya tanpa menyentuh keadaan global.
Menggunakan nama berbeda yang diawali garis bawah untuk setiap referensi nama membuat benturan tidak mungkin terjadi, bahkan ketika variabel pemanggil memiliki nama sederhana.
#!/usr/bin/env bash
filter_map_by_key_prefix() {
# Usage: filter_map_by_key_prefix src_map dest_map prefix
declare -n _src="$1"
declare -n _dst="$2"
local prefix="$3"
_dst=()
for key in "${!_src[@]}"; do
if [[ $key == ${prefix}* ]]; then
_dst["$key"]="${_src[$key]}"
fi
done
}
declare -A settings=(
[db_host]=localhost [db_port]=5432
[cache_ttl]=300 [cache_driver]=redis
[app_debug]=true
)
declare -A db_settings
filter_map_by_key_prefix settings db_settings db_
for k in "${!db_settings[@]}"; do
echo "$k = ${db_settings[$k]}"
doneUji Pemahaman: Referensi Nama dan Penerusan Larik
Uji pemahaman Anda tentang penerusan larik dan peta antar fungsi dalam Bash.
Rangkuman: Meneruskan Struktur Data Kompleks dalam Bash
Berikut hal-hal yang Anda pelajari dalam pelajaran ini:
- Larik tidak dapat diteruskan berdasarkan nilai — teruskan nama variabel sebagai string.
declare -n ref="$varname"membuat referensi nama: alias aktif ke variabel pemanggil. Pembacaan dan penulisan sama-sama diteruskan ke variabel asli. Memerlukan Bash 4.3+.- Benturan referensi nama terjadi ketika variabel internal dan eksternal memiliki nama yang sama. Cegah dengan mengawali referensi nama internal (misalnya,
_arr,_map). - Parameter keluaran bekerja dengan meneruskan nama larik/peta hasil yang kosong; fungsi mengisinya melalui referensi nama.
- Beberapa referensi nama dalam satu fungsi memungkinkan transformasi murni dari masukan ke keluaran tanpa efek samping global.
- Perluasan tidak langsung (
${!varname[@]}+eval) adalah pilihan cadangan lama untuk Bash < 4.3, tetapi membawa risiko injeksi dan pada praktiknya hanya dapat dibaca. - Gabungkan teknik-teknik ini dengan berkas pustaka yang dimuat untuk membangun basis kode Bash yang modular, dapat digunakan kembali, dan dapat diuji.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Meneruskan Larik dan Peta Asosiatif antar Fungsi” gratis?
Ya — teks lengkap “Meneruskan Larik dan Peta Asosiatif antar Fungsi” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Linux Command Line & Bash Scripting Mastery, upgrade ke CoddyKit PRO. Kursus Linux Command Line & Bash Scripting Mastery mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Meneruskan Larik dan Peta Asosiatif antar Fungsi”?
Gunakan nameref dan ekspansi tidak langsung untuk meneruskan struktur data kompleks ke dalam dan ke luar fungsi dengan aman. Kamu berlatih Linux Command Line & Bash Scripting Mastery dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Linux Command Line & Bash Scripting Mastery?
Tidak diperlukan pengalaman sebelumnya. Linux Command Line & Bash Scripting Mastery di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.
Berapa lama pelajaran “Meneruskan Larik dan Peta Asosiatif antar Fungsi” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Linux Command Line & Bash Scripting Mastery ini?
Ya. Setiap pelajaran Linux Command Line & Bash Scripting Mastery menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Merancang Fungsi dengan Lingkup Lokal dan Kode Kembalian
- Membangun dan Memuat Pustaka Bash yang Dapat Digunakan Ulang
- Mengurai Bendera dan Argumen dengan getopts
- Meneruskan Larik dan Peta Asosiatif antar Fungsi