Setelah Bab 2 membekali kita dengan perintah dasar untuk bergerak dan mengelola file lewat terminal, saatnya masuk ke fondasi yang membuat sebuah script Bash benar-benar layak disebut "program": variabel. Bab ini membahas cara mendeklarasikan dan membaca variabel, perbedaan mendasar antara shell variable dan environment variable, dua tipe data dasar yang dikenal Bash (string dan angka), sampai aturan quoting yang sering jadi sumber bug tersembunyi bagi pemula. Penguasaan topik ini adalah syarat mutlak sebelum masuk ke Bab 4 tentang array, karena array pada dasarnya adalah variabel yang menyimpan banyak nilai sekaligus.
3.1 Mendeklarasikan dan Menggunakan Variabel
Variabel adalah nama yang dipakai untuk menyimpan sebuah nilai supaya bisa dipanggil ulang tanpa harus menulis ulang nilainya berkali-kali. Konsepnya sama seperti mencatat nomor meja di secarik kertas alih-alih menghafal detail lengkap pemesanan setiap kali dibutuhkan: sekali dicatat dengan nama yang jelas, kita tinggal merujuk pada catatan itu di mana pun diperlukan.
3.1.1 Aturan Penamaan dan Assignment
Nama variabel di Bash hanya boleh terdiri dari huruf, angka, dan garis bawah (_), serta tidak boleh diawali angka. Bash juga bersifat case-sensitive, sehingga nama dan Nama dianggap sebagai dua variabel yang berbeda.
Aturan paling sering dilanggar pemula adalah soal spasi: assignment (=) tidak boleh diberi spasi di kedua sisinya.
nama="Budi"
umur=25Sesuai konvensi (bukan aturan wajib dari Bash), nama variabel biasa ditulis huruf kecil, sementara environment variable dan konstanta biasanya ditulis huruf kapital seluruhnya, seperti PATH atau HOME yang akan dibahas di sub-bab 3.2. Konvensi ini membantu kita membedakan sekilas mana variabel biasa dan mana yang berasal dari environment sistem.
3.1.2 Membaca Nilai dengan Tanda $ dan ${ }
Untuk membaca nilai sebuah variabel, tambahkan tanda dolar ($) di depan namanya.
nama="Budi"
echo $namaBentuk ${nama} dengan kurung kurawal punya efek yang sama, tapi wajib dipakai saat nama variabel langsung bersambung dengan karakter lain tanpa pemisah, supaya Bash tidak salah menafsirkan batas nama variabelnya.
file="laporan"
echo "${file}_final.txt"Tanpa kurung kurawal, echo "$file_final.txt" justru dianggap memanggil variabel bernama file_final yang belum pernah dideklarasikan, sehingga hasilnya kosong dan bukan laporan_final.txt seperti yang dimaksud.
3.1.3 readonly dan unset: Mengunci dan Menghapus Variabel
Jika sebuah variabel harus dipastikan tidak berubah nilainya sepanjang eksekusi script, misalnya untuk menyimpan konstanta konfigurasi, tandai dengan readonly.
readonly MAX_RETRY=5Setelah dideklarasikan readonly, percobaan mengubah atau menghapus variabel tersebut akan gagal dengan pesan error. Sebaliknya, untuk menghapus variabel biasa yang sudah tidak dibutuhkan, gunakan unset.
nama="Budi"
unset nama
echo $namaBaris terakhir di atas akan menampilkan output kosong, karena variabel nama sudah tidak lagi ada setelah di-unset.
3.1.4 Verifikasi dan Troubleshooting Assignment
Cara paling cepat memverifikasi isi sebuah variabel adalah lewat echo, atau lewat perintah declare -p yang juga menampilkan atribut tambahan variabel tersebut (misalnya apakah bertipe integer atau readonly, dibahas di sub-bab 3.3).
declare -p namaError paling umum yang ditemui pemula adalah bash: nama: command not found saat menulis nama = "Budi" dengan spasi di sekitar tanda sama dengan. Bash membaca nama sebagai nama perintah yang hendak dijalankan, bukan sebagai assignment variabel, persis karena aturan tanpa-spasi di sub-bab 3.1.1 dilanggar.
Di lapangan, kebiasaan lain yang perlu diwaspadai adalah memanggil variabel yang belum pernah dideklarasikan. Secara default Bash tidak memberi peringatan apa pun dan cukup menganggapnya sebagai string kosong, sehingga typo pada nama variabel bisa lolos tanpa terdeteksi sampai menyebabkan bug yang membingungkan. Opsi set -u yang membuat Bash berhenti dengan error saat menemukan variabel belum terdefinisi akan dibahas lebih dalam di Bab 25 tentang debugging dan error handling.
3.2 Environment Variable vs Shell Variable
Tidak semua variabel di Bash punya jangkauan yang sama. Sebagian hanya "hidup" di dalam shell tempat ia dideklarasikan, sebagian lagi ikut diwariskan ke setiap program baru yang dijalankan dari shell tersebut. Perbedaan ini penting dipahami karena banyak bug script yang ternyata berakar dari variabel yang dikira otomatis tersedia di proses lain, padahal tidak.
3.2.1 Shell Variable: Lokal untuk Shell Saat Ini
Shell variable adalah variabel biasa seperti yang dibahas di sub-bab 3.1, hanya dikenal oleh shell (atau script) tempat ia dideklarasikan. Ketika shell tersebut menjalankan program lain, misalnya memanggil script Bash lain atau perintah eksternal, program baru itu tidak bisa mengakses shell variable dari proses induknya.
pesan="Halo dari shell induk"
bash -c 'echo $pesan'Perintah di atas akan menampilkan baris kosong, karena bash -c menjalankan instance Bash yang sepenuhnya baru sebagai proses anak terpisah, sehingga tidak mewarisi variabel pesan dari shell induknya. Perlu dibedakan dengan subshell yang dibuat lewat tanda kurung seperti (echo $pesan): subshell adalah hasil fork dari proses shell yang sedang berjalan, sehingga tetap mewarisi seluruh shell variable milik induknya, bukan hanya yang sudah di-export. Perbedaan ini penting diingat karena subshell akan dipakai lagi saat membahas pipeline dan command grouping di Bab 7 dan Bab 12.
3.2.2 export: Menjadikannya Environment Variable
Agar sebuah variabel diwariskan ke proses anak, tandai dengan builtin export. Variabel yang sudah di-export inilah yang disebut environment variable.
export pesan="Halo dari shell induk"
bash -c 'echo $pesan'Kali ini perintah bash -c berhasil menampilkan isi variabel pesan, karena environment variable ikut disalin ke dalam environment block setiap proses anak yang dibuat dari shell tersebut. export juga bisa dipakai terhadap variabel yang sudah ada sebelumnya, tanpa perlu menuliskan ulang nilainya.
pesan="Halo lagi"
export pesanPerlu dicatat, pewarisan ini hanya berjalan satu arah: dari proses induk ke proses anak. Perubahan environment variable di dalam proses anak tidak akan pernah memengaruhi shell induk yang memanggilnya, karena setiap proses punya salinan environment-nya masing-masing.
3.2.3 Variabel Environment Penting: PATH, HOME, dan Lainnya
Banyak environment variable sudah otomatis tersedia begitu kita login, disiapkan oleh sistem atau shell itu sendiri. Tabel berikut merangkum beberapa yang paling sering dipakai.
| Variabel | Fungsi |
|---|---|
PATH | Daftar direktori (dipisah titik dua) yang dicari Bash saat menjalankan sebuah perintah tanpa path eksplisit |
HOME | Path home directory user yang sedang login, dirujuk juga lewat simbol ~ |
USER | Nama user yang sedang login |
SHELL | Path shell login default user, belum tentu sama dengan shell yang sedang aktif dipakai |
PWD | Direktori aktif saat ini, diperbarui otomatis oleh builtin cd |
OLDPWD | Direktori aktif sebelumnya, dipakai oleh cd - seperti dibahas di Bab 2 |
LANG | Pengaturan locale/bahasa sistem |
EDITOR | Text editor default yang dipanggil program lain, misalnya crontab -e |
PATH adalah salah satu yang paling krusial dipahami Sysadmin. Setiap kali kita mengetik nama perintah tanpa path, misalnya ls alih-alih /usr/bin/ls, Bash mencari executable bernama ls di setiap direktori yang terdaftar di PATH, berurutan dari kiri ke kanan, dan berhenti pada kecocokan pertama yang ditemukan.
echo $PATHMenambahkan direktori baru ke PATH, misalnya folder bin pribadi berisi script buatan sendiri, adalah kebutuhan umum baik untuk User maupun Sysadmin.
export PATH="$PATH:$HOME/bin"Di lapangan, urutan penulisan ini penting: menaruh direktori baru di akhir ($PATH:direktori-baru) berarti perintah bawaan sistem tetap diprioritaskan bila ada nama yang bentrok, sementara menaruhnya di awal (direktori-baru:$PATH) membuat perintah kita sendiri yang diprioritaskan. Sysadmin perlu berhati-hati dengan urutan ini, karena kesalahan susunan PATH bisa membuat script tanpa sengaja memanggil binary yang salah.
3.2.4 Melihat Seluruh Environment dengan env dan printenv
Untuk melihat seluruh environment variable yang aktif sekaligus, pakai env atau printenv tanpa argumen.
envprintenv juga bisa dipakai untuk menampilkan nilai satu variabel spesifik, mirip echo $VARIABEL, dengan satu perbedaan penting: printenv hanya mengenali environment variable yang sudah di-export, sementara echo $VARIABEL tetap bisa menampilkan shell variable biasa yang belum di-export.
printenv HOME3.2.5 Troubleshooting: Salah Mengatur PATH
Kesalahan yang cukup sering dialami pemula, dan kadang juga Sysadmin yang kurang berhati-hati, adalah menimpa PATH sepenuhnya alih-alih menambahkan direktori baru ke nilai yang sudah ada.
PATH=/opt/aplikasi-khusus/binAssignment di atas menghapus seluruh isi PATH sebelumnya dan menggantinya hanya dengan satu direktori, sehingga hampir semua perintah, termasuk perintah sesederhana ls, langsung gagal ditemukan.
ls
bash: line 1: ls: command not foundKesalahan ini untungnya hanya berlaku untuk shell yang sedang berjalan, bukan perubahan permanen, kecuali baris assignment yang salah tadi ditulis di file konfigurasi seperti .bashrc. Cara tercepat memulihkan diri di sesi yang sama adalah memanggil perintah lewat absolute path, yang tetap berfungsi normal karena tidak bergantung pada PATH sama sekali.
/bin/echo "Masih bisa jalan lewat absolute path"
export PATH=/usr/bin:/binJika tidak yakin nilai default PATH yang benar untuk sistem yang dipakai, cara paling aman adalah membuka jendela terminal baru, karena sesi baru akan memuat ulang PATH dari konfigurasi login secara normal. Pelajaran dari kasus ini: selalu tambahkan direktori baru dengan pola export PATH="$PATH:direktori-baru" seperti dibahas di sub-bab 3.2.3, jangan pernah menimpa PATH secara langsung.
3.3 Tipe Data Dasar: String dan Angka
Berbeda dari bahasa pemrograman seperti Python atau Java yang mengharuskan kita mendeklarasikan tipe data secara eksplisit, Bash menganut pendekatan yang jauh lebih longgar terhadap tipe data.
3.3.1 Bash Tanpa Tipe Data Ketat
Secara default, setiap variabel di Bash disimpan dan diperlakukan sebagai string, termasuk yang isinya berupa angka. Bash baru menafsirkan sebuah string sebagai angka pada konteks tertentu, misalnya di dalam arithmetic expansion yang akan dibahas di sub-bab 3.3.3.
umur="25"
echo $((umur + 5))Kode di atas tetap menghasilkan 30 meski umur secara teknis tersimpan sebagai string, karena konteks $(( )) memaksa Bash mengevaluasinya sebagai ekspresi aritmatika. Karakteristik "tanpa tipe ketat" ini praktis untuk script pendek, tapi juga jadi sumber bug yang sering luput, misalnya saat variabel yang seharusnya angka ternyata berisi string kosong atau teks tidak valid, dan baru ketahuan saat script sudah berjalan di production.
3.3.2 Bekerja dengan String
Karena semua variabel pada dasarnya string, operasi penggabungan (concatenation) string di Bash tidak butuh operator khusus seperti + di bahasa lain, cukup menuliskannya berdampingan.
nama_depan="Budi"
nama_belakang="Santoso"
nama_lengkap="$nama_depan $nama_belakang"
echo $nama_lengkapBash juga menyediakan berbagai manipulasi string lewat sintaks parameter expansion bawaan, seperti mengambil panjang string atau memotong sebagian isinya. Pembahasan lebih rinci soal manipulasi string, termasuk pencarian pola dengan regular expression, akan dibahas khusus di Bab 9.
echo ${#nama_lengkap}3.3.3 Arithmetic Expansion untuk Operasi Angka
Untuk operasi angka, Bash menyediakan arithmetic expansion lewat sintaks $(( expression )). Di dalam tanda kurung ganda ini, Bash mengevaluasi ekspresi matematika dan mengembalikan hasilnya.
hasil=$((10 + 5))
echo $hasilOperator yang didukung mencakup penjumlahan (+), pengurangan (-), perkalian (*), pembagian (/), sisa bagi/modulo (%), dan pemangkatan (**).
echo $((7 / 2))
echo $((7 % 2))
echo $((2 ** 3))Satu batasan penting yang wajib diketahui: Bash hanya mendukung bilangan bulat (integer) dalam operasi aritmatikanya, tidak ada dukungan native untuk bilangan pecahan (floating point). Perhatikan hasil 7 / 2 pada contoh di atas yang menghasilkan 3, bukan 3.5, karena hasil pembagian selalu dipotong (truncated) ke arah nol. Untuk kebutuhan operasi bilangan pecahan, kita perlu memakai tool eksternal seperti bc atau awk, yang akan disinggung lebih lanjut saat membahas awk di Bab 11.
echo "7 / 2" | bc -lSelain $(( )), ada juga bentuk (( expression )) tanpa tanda dolar yang dipakai sebagai perintah tersendiri, bukan untuk mengambil nilai hasilnya, melainkan untuk mengecek kebenaran sebuah kondisi lewat exit status. Bentuk ini sering dipakai di dalam struktur kondisi seperti if, yang akan dibahas di Bab 6.
angka=10
if (( angka > 5 )); then
echo "Lebih dari 5"
fi3.3.4 declare -i: Mendeklarasikan Variabel Integer
Builtin declare dengan flag -i memberi variabel atribut integer secara permanen. Setelah atribut ini diberikan, setiap assignment ke variabel tersebut otomatis dievaluasi sebagai ekspresi aritmatika, tanpa perlu membungkusnya dengan $(( )) lagi.
declare -i skor
skor="5 + 3"
echo $skorBaris di atas langsung menghasilkan 8, bukan menampilkan teks 5 + 3 apa adanya, karena atribut integer pada skor membuat Bash otomatis mengevaluasinya sebagai ekspresi matematika setiap kali nilai baru di-assign.
3.3.5 Troubleshooting: Nilai Non-Angka di Arithmetic Expansion
Karena arithmetic expansion mengharapkan isi variabel berupa bilangan atau ekspresi matematika yang valid, memasukkan string biasa ke dalamnya akan memicu error, bukan diam-diam diperlakukan sebagai angka nol atau diabaikan.
umur="dua puluh lima"
echo $((umur + 5))bash: dua puluh lima: syntax error in expression (error token is "puluh lima")Error semacam ini paling sering muncul saat nilai yang dipakai untuk operasi aritmatika sebenarnya berasal dari input user lewat read atau argumen script, yang isinya tidak divalidasi lebih dulu sebelum dipakai di dalam $(( )). Di lapangan, kebiasaan aman yang layak dibawa sejak awal adalah memvalidasi bahwa sebuah variabel benar-benar berisi angka sebelum memakainya dalam operasi aritmatika, terutama jika nilainya berasal dari luar script. Topik validasi input secara lebih menyeluruh akan dibahas khusus di Bab 23.
3.4 Quoting: Single Quote vs Double Quote vs Backtick/$()
Quoting adalah salah satu topik yang sering dianggap remeh oleh pemula, padahal salah pilih jenis quote adalah salah satu penyebab bug paling umum di script Bash, bahkan di kalangan Sysadmin berpengalaman sekalipun.
3.4.1 Masalah Word Splitting Tanpa Quoting
Saat sebuah variabel di-expand tanpa dibungkus quote sama sekali, Bash melakukan dua proses tambahan secara otomatis: word splitting (memecah nilai variabel menjadi beberapa kata berdasarkan spasi) dan pathname expansion alias globbing (menafsirkan karakter seperti * sebagai wildcard). Kedua proses ini bisa memicu perilaku tak terduga.
file="laporan bulanan.txt"
ls $fileKarena $file tidak di-quote, Bash memecah nilainya menjadi dua argumen terpisah, laporan dan bulanan.txt, sehingga ls justru mencari dua file yang tidak ada alih-alih satu file bernama laporan bulanan.txt.
3.4.2 Single Quote: Literal Sepenuhnya
Single quote ('...') membuat Bash memperlakukan semua karakter di dalamnya secara harfiah (literal), tanpa ekspansi apa pun, termasuk tanda dolar dan backslash.
nama="Budi"
echo 'Halo, $nama'Perintah di atas menampilkan teks Halo, $nama apa adanya, bukan Halo, Budi, karena single quote mencegah Bash melakukan ekspansi variabel sama sekali. Karena sifatnya yang benar-benar literal, satu-satunya karakter yang tidak bisa langsung dimasukkan ke dalam single quote adalah tanda kutip tunggal itu sendiri, butuh trik khusus untuk menyisipkannya.
echo 'Ini adalah tanda kutip tunggal: '\''contoh'\'''3.4.3 Double Quote: Ekspansi Tetap Berjalan
Double quote ("...") mencegah word splitting dan globbing, tapi tetap membiarkan ekspansi variabel, command substitution, dan arithmetic expansion berjalan seperti biasa.
nama="Budi"
echo "Halo, $nama"Kali ini hasilnya Halo, Budi, karena double quote tetap mengizinkan tanda dolar melakukan ekspansi variabel. Kembali ke contoh masalah word splitting di sub-bab 3.4.1, membungkus variabel dengan double quote menyelesaikan masalah tersebut.
file="laporan bulanan.txt"
ls "$file"Karena alasan inilah, kebiasaan terbaik yang layak dibawa sejak awal belajar adalah selalu membungkus pemanggilan variabel dengan double quote secara default, kecuali kita memang sengaja membutuhkan word splitting atau globbing terjadi.
3.4.4 Command Substitution: $() vs Backtick
Command substitution adalah mekanisme mengambil output sebuah perintah dan memakainya sebagai nilai, baik untuk disimpan ke variabel maupun disisipkan langsung ke perintah lain. Ada dua sintaks yang bisa dipakai: bentuk modern $(command), dan bentuk lama pakai backtick `command`.
tanggal_hari_ini=$(date +%Y-%m-%d)
echo "Hari ini: $tanggal_hari_ini"tanggal_hari_ini=`date +%Y-%m-%d`
echo "Hari ini: $tanggal_hari_ini"Kedua baris di atas menghasilkan output yang sama persis, tapi sintaks $() lebih disarankan dipakai untuk script baru karena dua alasan praktis: lebih mudah dibaca karena batas awal dan akhirnya jelas, serta lebih mudah di-nesting (disarangkan) untuk memanggil command substitution di dalam command substitution lain.
echo "Isi direktori saat ini: $(ls $(pwd))"Menyarangkan backtick untuk kasus serupa jauh lebih merepotkan, karena backtick bagian dalam harus di-escape dengan backslash agar tidak dianggap sebagai penutup backtick bagian luar, sesuatu yang tidak perlu dipusingkan sama sekali dengan $().
3.4.5 Studi Kasus: Risiko Unquoted Variable
Kebiasaan tidak meng-quote variabel bukan cuma soal word splitting yang mengganggu, tapi juga bisa menjadi celah keamanan nyata. Perhatikan sebuah script yang membangun perintah dari input yang tidak sepenuhnya dikontrol, misalnya nama file hasil input user.
nama_file="dokumen; rm -rf /tmp/cache"
eval "cat $nama_file"Tanpa quoting yang tepat dan kombinasi dengan eval, Attacker bisa menyisipkan karakter khusus shell seperti titik koma (;) ke dalam input untuk menjalankan perintah tambahan di luar yang dimaksud pembuat script, sebuah teknik yang dikenal sebagai command injection. Pembahasan mendalam soal mencegah command injection dan validasi input akan dibahas lebih jauh di Bab 23. Prinsip dasar yang bisa dipegang sejak Bab 3 ini: selalu bungkus variabel dengan double quote saat dipakai sebagai argumen perintah, dan hindari eval terhadap string yang sebagian isinya berasal dari input luar yang tidak tepercaya.

