Belajar BASH Scripting - Pengenalan dan Penjelasan Functions
Episode 13 of 27

Belajar BASH Scripting - Pengenalan dan Penjelasan Functions

Membungkus logika berulang menjadi blok yang bisa dipanggil ulang dengan functions: sintaks deklarasi, lingkup variabel global vs `local`, argumen `$1 $2`, dan nilai balik via `return` serta `echo` + command substitution. Dilengkapi praktik membangun pustaka fungsi log, cek file, dan verifikasi root beserta jebakan yang sering menjebak.

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

Pendahuluan

Setelah di episode 12 sebelumnya kita menguasai perulangan while dan until serta membaca file baris demi baris, pada episode kali ini kita mengangkat satu masalah yang pasti mulai kalian rasakan: kode yang semakin panjang dan berulang. Pola yang sama — menulis log, memeriksa apakah sebuah file ada, memvalidasi hak akses root — mulai muncul berulang-ulang di berbagai bagian script.

Di sinilah functions berperan. Bayangkan sebuah dapur profesional: setiap juru masak tidak menulis ulang resep dari nol setiap kali ada pesanan masuk. Resepnya disimpan sekali, dan dipanggil namanya — "ayam bakar" — kapan pun dibutuhkan. Functions adalah resep-resep itu: kalian menulis logika sekali, memberi nama, lalu memanggilnya sesering mungkin dari mana pun.

Functions mengubah script dari sekadar daftar perintah linier menjadi arsitektur yang terstruktur: logika dibungkus, diberi nama, diuji sekali, dan dipakai di banyak tempat. Ini prinsip DRY (Don't Repeat Yourself) yang sama yang berlaku di semua bahasa pemrograman. Pada episode ini kita akan membedah sintaks fungsi Bash, lingkup variabel, cara mengirim dan mengambil nilai, hingga membangun pustaka fungsi yang bisa dipakai ulang antar script.

Pembahasan Utama

Mengapa Functions?

Sebelum membahas sintaks, mari kita pahami masalah apa yang dipecahkan functions. Perhatikan tiga keuntungan utamanya:

  1. Reusability (penggunaan ulang) — logika ditulis sekali, dipakai berkali-kali. Saat aturan log berubah, kalian cukup mengubah satu tempat, bukan sepuluh tempat.
  2. Readability (keterbacaan) — script yang dipenuhi blok perintah panjang sulit dibaca. Functions mengubah do_a_lot_of_stuff() menjadi nama yang menjelaskan dirinya sendiri, sehingga alur utama script jadi ringkas.
  3. Testability (keterujian) — fungsi kecil yang mandiri bisa diuji satu per satu sebelum digabung, jauh lebih mudah daripada men-debug satu script monolitik 500 baris.

Tanpa functions, script kalian akan terus menumpuk duplikasi seperti fotokopi yang menumpuk di meja kerja — satu perubahan pada aturan log berarti mencari dan memperbaiki semua fotokopi. Dengan functions, satu perbaikan di sumber langsung memperbaiki semua pemanggil.

Sintaks Dasar: nama() { ... }

Ada dua gaya penulisan fungsi di Bash — gaya POSIX nama() dan gaya dengan kata kunci function:

Dua gaya deklarasi fungsi
sapa() {
    echo "Halo, selamat datang!"
}
 
function ucap_terima_kasih {
    echo "Terima kasih sudah datang!"
}
Gaya nama() lebih portabel, gaya function lebih eksplisit

Untuk proyek yang harus portabel antar shell, gaya nama() adalah pilihan teraman. Gaya function adalah ekstensi Bash yang tidak ada di POSIX sh (ingat: kalian bisa saja mengetik bash script.sh, tapi script yang menargetkan sh harus menghindarinya).

Memanggil fungsi semudah menulis namanya — tanpa tanda kurung:

Memanggil fungsi
sapa() {
    echo "Halo, selamat datang!"
}
 
sapa
sapa
sapa
# Output: tiga kali "Halo, selamat datang!"
Panggil fungsi cukup dengan namanya, tanpa ()

Dua catatan penting yang membedakan Bash dari kebanyakan bahasa lain:

  • Panggilan tanpa ()sapa() hanya untuk mendeklarasikan, bukan memanggil. Memanggil cukup sapa.
  • Fungsi harus dideklarasikan sebelum dipanggil. Bash mengeksekusi script baris demi baris dari atas. Jika sapa dipanggil sebelum deklarasi sapa(), Bash akan mencari perintah bernama sapa — dan karena tidak ada, muncul error command not found.

Lingkup Variabel: Global vs local

Ini salah satu perbedaan paling penting antara Bash dan bahasa modern: variabel di Bash bersifat global secara default — bahkan di dalam fungsi. Variabel yang diubah di dalam fungsi tetap mengubah nilainya setelah fungsi selesai:

Variabel global berubah di dalam fungsi
warna="biru"
 
catat_warna() {
    warna="merah"
    echo "Di dalam fungsi: $warna"
}
 
catat_warna
echo "Di luar fungsi : $warna"
# Di dalam fungsi: merah
# Di luar fungsi : merah   <- nilainya ikut berubah!
Ubah warna di dalam fungsi = mengubah warna di luar fungsi

Ini adalah efek samping yang sering tidak diinginkan — fungsi yang tidak sengaja menimpa variabel global bisa merusak state script secara misterius. Solusinya: deklarasikan variabel yang hanya dipakai di dalam fungsi dengan kata kunci local:

Mengunci variabel dengan local
warna="biru"
 
catat_warna() {
    local warna="merah"
    echo "Di dalam fungsi: $warna"
}
 
catat_warna
echo "Di luar fungsi : $warna"
# Di dalam fungsi: merah
# Di luar fungsi : biru   <- aman!
local menjaga warna luar tetap biru

local membuat variabel itu hidup hanya selama fungsi berjalan dan menghilang setelahnya — seperti catatan tempel yang dibuang begitu tugas selesai, tidak meninggalkan bekas di meja kerja.

Important

Selalu gunakan local untuk variabel yang hanya dibutuhkan di dalam fungsi. Ini adalah disiplin yang memisahkan penulis script amatir dari yang profesional. Variabel global di luar fungsi tetap boleh — untuk konfigurasi bersama seperti LOG_DIR atau TIMEOUT — tetapi jangan pernah membiarkan fungsi mencemari variabel yang tidak disengaja. Aturannya: defaultkan local, global hanya untuk yang memang dibagi.

Argumen Fungsi: $1, $2, dst.

Fungsi yang kaku — selalu melakukan hal yang sama — baru setengah berguna. Agar fleksibel, fungsi perlu menerima masukan. Caranya: berikan argumen saat memanggil, dan baca di dalam fungsi lewat $1, $2, $3:

Fungsi dengan argumen
tambah() {
    local a="$1"
    local b="$2"
    local hasil=$((a + b))
    echo "Hasil: $a + $b = $hasil"
}
 
tambah 5 3
tambah 100 200
Argumen fungsi bersifat lokal, tidak mengganggu $1 script

Perhatikan dua hal penting:

  1. $1, $2 di dalam fungsi mengacu pada argumen fungsi, bukan argumen script. Ini kesalahan yang sangat umum: pemula membaca $1 di dalam fungsi lalu mengira itu argumen pertama script. Faktanya, saat fungsi dipanggil, $1 sementara diganti dengan argumen pertama fungsi — dan pulih kembali setelah fungsi selesai. Inilah alasan mengapa variabel-variabel ini aman dipakai di dalam fungsi tanpa local.
  2. Tidak ada batasan keras jumlah argumen. Kalian bisa mengoper $1 sampai $9, lalu $10, $11, dan seterusnya — dan "$@" di dalam fungsi menampung semua argumen fungsi sebagai daftar terpisah.

Tip

Untuk fungsi yang menerima banyak argumen, segera salin ke variabel bernama di awal: local src="$1"; local dst="$2". Ini mengubah $1, $2 yang misterius menjadi src dan dst yang menjelaskan diri sendiri — dan menjaga argumen asli tidak berubah jika ada pemanggilan fungsi lain di tengah jalan. Fungsi yang baik adalah fungsi yang 5 baris pertamanya mendokumentasikan apa yang diterimanya.

return vs Mengembalikan String

Fungsi di Bash bisa "memberi hasil kembali" lewat dua cara yang sangat berbeda, dan memahami bedanya akan menyelamatkan kalian dari bug yang membingungkan.

return mengembalikan exit status — bukan nilai. Ia menerima angka 0255, dan angka itu menjadi exit status fungsi yang bisa dibaca dengan $? atau diuji dalam kondisi:

return mengembalikan exit status
cek_file() {
    if [ -f "$1" ]; then
        return 0
    fi
    return 1
}
 
if cek_file "/etc/hostname"; then
    echo "File ditemukan."
else
    echo "File tidak ditemukan."
fi
return 0 = sukses, return 1 = gagal

return 0 menandakan sukses, return dengan nilai lain (biasanya 1) menandakan gagal. Inilah mengapa fungsi bisa langsung dipakai di dalam if — Bash menguji exit status-nya.

Untuk mengembalikan data (string), gunakan echo + command substitution:

Mengembalikan string dengan echo
get_ext() {
    local file="$1"
    echo "${file##*.}"
}
 
ekstensi=$(get_ext "laporan.pdf")
echo "Ekstensi: $ekstensi"
# Ekstensi: pdf
Command substitution menangkap output fungsi sebagai nilai

Di sini get_ext tidak "mengembalikan" apa pun secara formal — ia mencetak ke stdout, dan $( ... ) (command substitution, sudah kita bahas di episode tentang ekspansi) menangkap semua output itu sebagai string.

Warning

Jangan pernah mencoba mengembalikan string lewat returnreturn "halo" akan error (numeric argument required) karena return hanya menerima angka exit status. Dan jangan mencampur dua gaya: jika sebuah fungsi harus mengembalikan string, jangan tambahkan echo pembantu di tengah jalan, karena semua echo akan ikut tertangkap oleh command substitution. Pilih satu: fungsi itu pengembali status (return), atau pengembali data (echo), jangan keduanya campur.

Praktik: Membangun Pustaka Fungsi

Sekarang kita rangkai semuanya dalam studi kasus yang sangat nyata: sebuah pustaka fungsi (lib.sh) yang bisa di-source dari script mana pun. Pustaka berisi tiga fungsi yang selalu dibutuhkan script produksi: menulis log dengan timestamp, memeriksa keberadaan file, dan memverifikasi hak akses root:

lib.sh — pustaka fungsi umum
#!/usr/bin/env bash
 
log_info() {
    local msg="$1"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO  : $msg"
}
 
log_error() {
    local msg="$1"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR : $msg" >&2
}
 
is_file() {
    [ -f "$1" ]
}
 
check_root() {
    if [ "$(id -u)" -ne 0 ]; then
        log_error "Script harus dijalankan sebagai root."
        return 1
    fi
    return 0
}
Setiap variabel lokal, setiap hasil lewat return atau echo

Cara memakai pustaka ini dari script utama adalah dengan source (alias .), lalu panggil fungsinya seolah-olah didefinisikan di tempat:

script utama memakai pustaka
#!/usr/bin/env bash
source "$(dirname "$0")/lib.sh"
 
if ! check_root; then
    exit 1
fi
 
if is_file "/etc/hostname"; then
    log_info "/etc/hostname ada, lanjut konfigurasi."
else
    log_error "/etc/hostname tidak ditemukan."
    exit 1
fi
source membuat fungsi lib.sh tersedia di script ini

Perhatikan pola-pola yang telah kita pelajari bersatu di sini:

  • check_root memakai $() (command substitution) untuk mengambil output id -u, lalu membandingkannya dengan 0.
  • is_file adalah fungsi penguji — ia mengeksekusi [ -f "$1" ] dan exit status test itulah yang menjadi exit status fungsi. Ringkas dan idiomatis.
  • log_error menulis ke stderr (>&2) — keputusan penting: log yang salah dibedakan dari log normal sehingga bisa dipisahkan dalam pipeline dan file log.
  • source "$(dirname "$0")/lib.sh" memuat pustaka dari direktori script yang sama, tidak peduli dari mana script dipanggil.

Kesalahan Umum dalam Functions

KesalahanGejalaSolusi
Memanggil fungsi sebelum dideklarasikancommand not foundDeklarasikan fungsi di atas pemanggilannya
Lupa localVariabel fungsi mencemari globallocal untuk semua variabel internal
return "string" untuk datanumeric argument requiredreturn hanya angka status; pakai echo untuk string
Memakai $1 script di dalam fungsiArgumen salah / tak terduga$1 di fungsi adalah argumen fungsi, salin ke nama jelas
function di script target shError di shell lainPakai gaya nama()
Fungsi memakai variabel global tak terdugaBug samar yang sulit dilacakCek semua variabel fungsi sudah local

Note

Ada satu jebakan scoping lain yang sering dianggap mistis: fungsi yang dipanggil di dalam pipeline juga berjalan di subshell (ingat episode 12). Jika sebuah fungsi mengubah variabel global, lalu dipanggil dari dalam cat file | my_func, perubahannya hilang begitu pipeline selesai. Ini perilaku subshell yang sama — bukan bug Bash. Untuk fungsi yang harus mengubah state global, panggil di luar pipeline atau gunakan teknik yang sama seperti solusi subshell di episode 12.

Penutup

Pada episode 13 ini kita telah mengubah cara kalian menulis script: dari daftar perintah linier menjadi arsitektur berbasis fungsi. Kita membahas sintaks nama() { ... }, alasan mengapa fungsi itu penting (reuse, readability, testability), lingkup variabel dengan local yang wajib untuk variabel internal, pengiriman argumen lewat $1 $2, serta dua cara "mengembalikan nilai" — return untuk exit status dan echo + command substitution untuk string. Semuanya dirangkai dalam pustaka fungsi lib.sh yang siap di-source di script mana pun.

Prinsip yang harus kalian bawa pulang: fungsi yang baik itu kecil, ber-nama jelas, semua variabelnya local, dan hanya punya satu cara mengembalikan hasil. Jika sebuah fungsi sudah lebih dari 40 baris atau mengerjakan tiga hal sekaligus, pecahlah.

Setelah bisa membungkus logika, ada satu bahan yang masih kurang untuk automation tingkat lanjut: menyimpan banyak data dalam satu variabel. Di episode 14 selanjutnya kita akan membahas indexed array — cara menyimpan daftar nilai dalam satu variabel, mengaksesnya dengan indeks, mengiterasi seluruh elemen, menambahkan, memotong, hingga membangun daftar dari output perintah. Di sanalah daftar server, daftar file backup, dan koleksi data lain akan terasa sangat ringan ditangani. Sampai jumpa di episode berikutnya!

Belajar BASH Scripting - Pengenalan dan Penjelasan Functions | Belajar BASH Scripting