0Pricing
Linux Command Line & Bash Scripting Mastery · Pelajaran

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 Linux Command Line & Bash Scripting Mastery 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 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 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 local dapat diam-diam menimpa variabel pemanggil.
  • Variabel local dihapus 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 — berhasil
  • return 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
done

Mengomunikasikan 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:

  • printf tidak menambahkan baris baru di akhir secara bawaan (kecuali Anda menyertakan \n).
  • Perilaku printf konsisten dan didefinisikan oleh POSIX; echo berbeda-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: printf hasilnya dan jalankan return 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)."
fi

Menggunakan '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)"
done

Menghindari 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" menjadikan ref sebagai alias untuk variabel yang namanya tersimpan di $1.
  • Menetapkan nilai ke ref di 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 menjalankan return, 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
fi

Memvalidasi 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: $?"
fi

Menggabungkan Semuanya: Contoh di Dunia Nyata

Berikut skrip lengkap yang berdiri sendiri dan mendemonstrasikan semua konsep dari pelajaran ini secara bersamaan:

  • Variabel local di setiap fungsi.
  • Kode keluar untuk menandai keberhasilan/kegagalan.
  • printf untuk 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
}

main

Pemeriksaan 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 local untuk 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 dengan if, &&, dan ||.
  • Gunakan printf ke 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 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 “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 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 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 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

  1. Merancang Fungsi dengan Lingkup Lokal dan Kode Kembalian
  2. Membangun dan Memuat Pustaka Bash yang Dapat Digunakan Ulang
  3. Mengurai Bendera dan Argumen dengan getopts
  4. Meneruskan Larik dan Peta Asosiatif antar Fungsi
← Kembali ke Linux Command Line & Bash Scripting Mastery