Merancang Fungsi dengan Lingkup Lokal dan Kode Kembalian
Tulis fungsi yang menggunakan variabel lokal, status keluar, dan nilai kembalian berbasis printf alih-alih global yang rapuh.
Merancang Fungsi dengan Lingkup Lokal dan Kode Kembalian adalah pelajaran DevOps Bootcamp gratis di CoddyKit. Ini adalah pelajaran 1 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 DevOps Bootcamp, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus DevOps Bootcamp mencakup 4 pelajaran total.
Mengapa Cakupan Fungsi Itu Penting
Dalam Bash, variabel secara bawaan bersifat global. Variabel yang ditetapkan di dalam fungsi akan bocor ke cakupan pemanggil, kecuali Anda secara eksplisit mendeklarasikannya sebagai local. Ini merupakan sumber umum bug terselubung dalam skrip shell.
- Fungsi tanpa
localdapat diam-diam menimpa variabel pemanggil. - Variabel
localdihapus saat fungsi selesai. - Batas cakupan yang jelas membuat fungsi dapat digunakan kembali dan diuji secara terpisah.
Pelajaran ini mengajarkan Anda menulis fungsi yang mandiri: fungsi tersebut menggunakan variabel local, menyampaikan hasil melalui kode keluar dan printf, serta tidak pernah bergantung pada keadaan global implisit.
Masalah Kebocoran Global
Berikut contoh konkret kebocoran variabel global. Fungsi set_name menetapkan variabel bernama result, yang secara diam-diam menimpa variabel result milik pemanggil.
Jalankan skrip ini dan amati keluarannya yang tidak terduga — result milik pemanggil hilang setelah pemanggilan fungsi.
#!/usr/bin/env bash
set_name() {
result="Alice" # No 'local' — this is GLOBAL
}
result="important data"
echo "Before: $result"
set_name
echo "After: $result" # Prints 'Alice', not 'important data'Mendeklarasikan Variabel Lokal dengan 'local'
Bawaan local membatasi cakupan variabel ke fungsi yang mencakupnya dan fungsi apa pun yang dipanggilnya. Di luar fungsi tersebut, variabel akan tidak ditetapkan atau mempertahankan nilai sebelumnya.
local varname— mendeklarasikan tanpa menetapkan nilai.local varname="value"— mendeklarasikan dan menetapkan nilai dalam satu langkah.local -i count=0— mendeklarasikan variabel lokal bertipe bilangan bulat.local -r PI=3.14159— mendeklarasikan konstanta lokal hanya-baca.
Praktik terbaik: deklarasikan setiap variabel di dalam fungsi sebagai local, kecuali jika Anda memang memerlukannya sebagai variabel global.
#!/usr/bin/env bash
greet() {
local name="$1" # local — safe
local greeting="Hello, ${name}!"
echo "$greeting"
} # 'name' and 'greeting' vanish here
name="global value"
greet "Bob"
echo "name is still: $name" # Prints 'global value'Kode Keluar sebagai Nilai Pengembalian
Fungsi Bash tidak dapat mengembalikan string dengan return — return hanya menetapkan status keluar bilangan bulat (0–255). Berdasarkan konvensi:
return 0— berhasilreturn 1(atau nilai bukan nol apa pun) — gagal
Pemanggil membaca status keluar melalui $? segera setelah pemanggilan, atau menggunakan fungsi tersebut langsung dalam kondisi if. Kode keluar adalah cara yang lazim untuk memberi sinyal keberhasilan atau kegagalan dari sebuah fungsi.
#!/usr/bin/env bash
is_even() {
local -i n="$1"
(( n % 2 == 0 )) # arithmetic command: exits 0 if true, 1 if false
}
for num in 2 3 7 10; do
if is_even "$num"; then
echo "$num is even"
else
echo "$num is odd"
fi
doneMengomunikasikan Hasil String melalui printf
Saat fungsi perlu mengembalikan hasil string, pola standarnya adalah mencetak ke keluaran standar lalu menangkapnya dengan substitusi perintah $(). Penggunaan printf, bukan echo, lebih disarankan karena:
printftidak menambahkan baris baru di akhir secara bawaan (kecuali Anda menyertakan\n).- Perilaku
printfkonsisten dan didefinisikan oleh POSIX;echoberbeda-beda antar-shell. - Substitusi perintah menghapus baris baru di akhir, sehingga
printf '%s' "$value"bersifat presisi.
#!/usr/bin/env bash
to_uppercase() {
local input="$1"
printf '%s' "${input^^}" # Bash 4+ parameter expansion
}
word="hello"
upper=$(to_uppercase "$word")
echo "Original: $word"
echo "Upper: $upper"Menggabungkan Kode Keluar dan Keluaran stdout
Fungsi yang dirancang dengan baik dapat sekaligus mencetak hasil (saat berhasil) dan menandai kegagalan (melalui kode keluar). Pemanggil menentukan tindakan berdasarkan kode keluar sebelum mempercayai keluarannya.
Pola berikut banyak digunakan dalam pustaka Bash nyata:
- Saat berhasil:
printfhasilnya dan jalankanreturn 0. - Saat gagal: tulis informasi diagnostik ke stderr (bukan stdout) dan jalankan
return 1. - Menulis galat ke stderr menjaga stdout tetap bersih untuk penyaluran.
#!/usr/bin/env bash
divide() {
local -i numerator="$1"
local -i denominator="$2"
if (( denominator == 0 )); then
printf 'Error: division by zero\n' >&2
return 1
fi
printf '%d' $(( numerator / denominator ))
return 0
}
if result=$(divide 20 4); then
echo "20 / 4 = $result"
else
echo "Division failed."
fi
if result=$(divide 10 0); then
echo "10 / 0 = $result"
else
echo "Division failed (caught the error)."
fiMenggunakan 'local' untuk Melindungi Fungsi Rekursif
Rekursi adalah salah satu demonstrasi paling jelas tentang alasan local sangat penting. Setiap pemanggilan rekursif mendapatkan salinan independen dari setiap variabel local di tumpukan pemanggilan. Tanpa local, setiap pemanggilan akan menimpa variabel global yang sama dan menghasilkan hasil yang salah.
Fungsi faktorial di bawah ini aman karena n dan sub bersifat lokal pada setiap bingkai tumpukan.
#!/usr/bin/env bash
factorial() {
local -i n="$1"
local -i sub
if (( n <= 1 )); then
printf '1'
return 0
fi
sub=$(factorial $(( n - 1 )))
printf '%d' $(( n * sub ))
}
for i in 1 2 3 4 5 6; do
echo "${i}! = $(factorial $i)"
doneMenghindari Perangkap Sub-shell dengan local -n (Referensi Nama)
Substitusi perintah $() berjalan dalam sub-shell. Penetapan variabel apa pun di dalamnya tidak terlihat oleh shell induk. Saat Anda perlu membuat fungsi menulis ke variabel yang disediakan pemanggil tanpa menggunakan sub-shell, gunakan referensi nama (local -n), yang tersedia di Bash 4.3+.
local -n ref="$1"menjadikanrefsebagai alias untuk variabel yang namanya tersimpan di$1.- Menetapkan nilai ke
refdi dalam fungsi akan langsung mengubah variabel milik pemanggil. - Dengan demikian, sub-shell dapat dihindari sementara detail implementasi tetap bersifat lokal.
#!/usr/bin/env bash
# Fills caller's array by reference — no subshell needed
read_csv_line() {
local -n _out="$1" # nameref to caller's variable
local line="$2"
local IFS=','
read -ra _out <<< "$line"
}
declare -a fields
read_csv_line fields "alice,30,engineer"
echo "Name: ${fields[0]}"
echo "Age: ${fields[1]}"
echo "Role: ${fields[2]}"Membangun Pustaka Fungsi Kecil
Proyek Bash di dunia nyata memisahkan fungsi yang dapat digunakan kembali ke dalam berkas pustaka yang dimuat oleh skrip dengan source (atau operator titik .). Aturan desain pustaka yang baik:
- Setiap variabel di dalam fungsi pustaka harus berupa
local. - Fungsi pustaka tidak pernah menjalankan
exit— fungsi tersebut menjalankanreturn, sehingga pemanggil tetap berjalan. - Gunakan awalan ruang nama yang konsisten (misalnya,
str_,log_) untuk menghindari benturan nama. - Lindungi dari pemuatan ganda dengan variabel penanda.
Berikut pustaka utilitas string minimal yang mengikuti konvensi ini.
#!/usr/bin/env bash
# lib/str.sh — string utility library
[[ -n "${_LIB_STR_LOADED:-}" ]] && return 0
_LIB_STR_LOADED=1
str_trim() {
local str="$1"
str="${str#"${str%%[![:space:]]*}"}"
str="${str%"${str##*[![:space:]]}"}"
printf '%s' "$str"
}
str_repeat() {
local -i times="$2"
local char="$1"
local -i i
for (( i = 0; i < times; i++ )); do
printf '%s' "$char"
done
}
str_contains() {
local haystack="$1"
local needle="$2"
[[ "$haystack" == *"$needle"* ]]
}
# --- self-test when executed directly ---
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
trimmed=$(str_trim " hello world ")
echo "Trimmed: '${trimmed}'"
str_repeat '-' 20; echo
if str_contains "bash scripting" "script"; then
echo "Contains: yes"
fi
fiMemvalidasi Argumen di Dalam Fungsi
Fungsi yang menerima argumen sebaiknya memvalidasinya sejak awal dan mengembalikan kode keluar tertentu jika masukan tidak valid. Ini disebut pola klausa penjaga — gagal lebih awal dan dengan jelas.
- Periksa jumlah argumen dengan
$#. - Validasi tipe atau format sebelum melakukan pekerjaan apa pun.
- Cetak pesan diagnostik hanya ke stderr, jangan pernah ke stdout.
- Gunakan kode pengembalian bukan nol yang berbeda (misalnya, 1 = argumen salah, 2 = berkas tidak ditemukan) agar pemanggil dapat menanggapi berbagai jenis kegagalan secara berbeda.
#!/usr/bin/env bash
file_line_count() {
if (( $# != 1 )); then
printf 'Usage: file_line_count <file>\n' >&2
return 1
fi
local file="$1"
if [[ ! -f "$file" ]]; then
printf 'Error: not a file: %s\n' "$file" >&2
return 2
fi
if [[ ! -r "$file" ]]; then
printf 'Error: cannot read: %s\n' "$file" >&2
return 3
fi
local -i count
count=$(wc -l < "$file")
printf '%d' "$count"
return 0
}
# Test with /etc/hosts (exists on every Linux/macOS system)
if lines=$(file_line_count /etc/hosts); then
echo "/etc/hosts has $lines lines"
else
echo "Failed with exit code: $?"
fiMenggabungkan Semuanya: Contoh di Dunia Nyata
Berikut skrip lengkap yang berdiri sendiri dan mendemonstrasikan semua konsep dari pelajaran ini secara bersamaan:
- Variabel
localdi setiap fungsi. - Kode keluar untuk menandai keberhasilan/kegagalan.
printfuntuk mengomunikasikan hasil string.- Galat ditulis ke stderr, hasil ke stdout.
- Klausa penjaga untuk validasi argumen.
Pelajari alurnya: parse_version mengekstrak data, version_ge membandingkannya, dan main menggunakan keduanya dengan rapi.
#!/usr/bin/env bash
# Parse a semver string into components via nameref
parse_version() {
local -n _major="$2" _minor="$3" _patch="$4"
local version="$1"
local IFS='.'
local -a parts
read -ra parts <<< "$version"
_major="${parts[0]:-0}"
_minor="${parts[1]:-0}"
_patch="${parts[2]:-0}"
}
# Return 0 if version $1 >= version $2
version_ge() {
local -i maj_a min_a pat_a
local -i maj_b min_b pat_b
parse_version "$1" maj_a min_a pat_a
parse_version "$2" maj_b min_b pat_b
if (( maj_a != maj_b )); then (( maj_a > maj_b ))
elif (( min_a != min_b )); then (( min_a > min_b ))
else (( pat_a >= pat_b ))
fi
}
require_bash_version() {
local required="$1"
local actual="${BASH_VERSION%%(*}"
if version_ge "$actual" "$required"; then
printf 'Bash %s satisfies >= %s\n' "$actual" "$required"
return 0
else
printf 'Error: need Bash >= %s, got %s\n' "$required" "$actual" >&2
return 1
fi
}
main() {
require_bash_version "4.3" || return 1
require_bash_version "99.0" || true # demonstrates failure path
}
mainPemeriksaan Pengetahuan: Variabel Lokal dan Nilai Pengembalian
Perhatikan fungsi Bash berikut. Bagaimana cara yang benar untuk menangkap hasil stringnya di pemanggil, dan pernyataan mana tentang variabel tmp yang benar?
transform() {
local tmp="${1,,}" # lowercase
printf '%s' "$tmp"
return 0
}Rangkuman: Fungsi dengan Cakupan Lokal dan Kode Pengembalian
Dalam pelajaran ini, Anda mempelajari cara menulis fungsi Bash yang rapi, dapat dikomposisikan, dan aman:
- Selalu gunakan
localuntuk variabel di dalam fungsi agar tidak mengotori cakupan pemanggil. - Gunakan kode keluar (
return 0/1/N) untuk menandai keberhasilan atau kegagalan — kode ini terintegrasi secara alami denganif,&&, dan||. - Gunakan
printfke stdout untuk mengomunikasikan hasil string; tangkap hasil tersebut dengan$()di pemanggil. - Tulis galat ke stderr (
>&2) agar stdout tetap bersih untuk aliran data dan penyaluran. - Gunakan
local -n(referensi nama) saat Anda perlu menulis ke variabel yang disediakan pemanggil tanpa beban penggunaan sub-shell. - Klausa penjaga (memvalidasi argumen sejak awal dan segera mengembalikan hasil saat masukan tidak valid) membuat fungsi tangguh dan mendokumentasikan dirinya sendiri.
- Berkas pustaka sebaiknya dimuat, menggunakan awalan ruang nama, tidak pernah memanggil
exit, dan terlindung dari pemuatan ganda.
Menguasai pola-pola ini adalah pembeda antara skrip sekali pakai yang rapuh dan basis kode Bash profesional yang mudah dipelihara.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Merancang Fungsi dengan Lingkup Lokal dan Kode Kembalian” gratis?
Ya — teks lengkap “Merancang Fungsi dengan Lingkup Lokal dan Kode Kembalian” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus DevOps Bootcamp, upgrade ke CoddyKit PRO. Kursus DevOps Bootcamp mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Merancang Fungsi dengan Lingkup Lokal dan Kode Kembalian”?
Tulis fungsi yang menggunakan variabel lokal, status keluar, dan nilai kembalian berbasis printf alih-alih global yang rapuh. Kamu berlatih DevOps Bootcamp 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 DevOps Bootcamp?
Tidak diperlukan pengalaman sebelumnya. DevOps Bootcamp 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 1 dari 4.
Berapa lama pelajaran “Merancang Fungsi dengan Lingkup Lokal dan Kode Kembalian” 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 DevOps Bootcamp ini?
Ya. Setiap pelajaran DevOps Bootcamp 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