Belajar BASH Scripting - Command Line Arguments & Special Parameters
Episode 5 of 27

Belajar BASH Scripting - Command Line Arguments & Special Parameters

Menguasai cara mengoper data dari luar ke dalam skrip melalui positional parameters ($1, $2, ${10}), memahami special parameters ($0, $#, $@, $*, $, $?), serta memakai shift untuk mengonsumsi argumen secara berurutan beserta jebakan-jebakan yang paling sering membuat skrip gagal diam-diam.

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

Pendahuluan

Setelah di episode 4 sebelumnya kita membahas quoting, escaping & word splitting — bagaimana kutip tunggal, kutip ganda, dan backslash mengendalikan cara bash memecah string menjadi kata-kata, serta mengapa "$@" lebih aman daripada $@ — pada episode kali ini kita naik satu tingkat: mengoper data dari luar ke dalam skrip.

Sebuah skrip yang hanya bekerja dengan nilai yang diketik langsung di dalam kodenya sama seperti mesin kasir yang hanya bisa menghitung nominal "10000" terus-menerus. Tidak berguna, bukan? Untuk itu, kita perlu mempelajari bagaimana skrip menerima argument baris perintah (command line arguments) dan memanfaatkan special parameters bawaan bash. Ini adalah fondasi yang membuat skrip kalian bisa dipakai berulang kali dengan data yang berbeda — tanpa mengubah satu baris kode pun.

Pembahasan Utama

Mengapa Skrip Perlu Menerima Argumen?

Perhatikan perintah yang sudah sering kalian pakai: cp file.txt backup/, rm -rf cache/, systemctl restart nginx. Ketiga perintah itu tidak meminta data lewat dialog atau menu — mereka menerima argumen langsung di baris perintah. Inilah paradigma Unix: perintah kecil yang serba guna, dikonfigurasi lewat argumen, bukan perintah raksasa yang menanyakan semuanya satu per satu.

Bayangkan kalian membuat skrip backup.sh untuk mem-backup direktori. Ada dua cara menuliskannya:

#!/usr/bin/env bash
tar -czf /home/arman/backup.tar.gz /home/arman/Projects
echo "Backup selesai."

Versi pertama hanya bisa mem-backup satu folder, selamanya. Versi kedua bisa dipakai untuk folder apa pun: ./backup.sh /tmp/backup.tar.gz /home/arman/Projects. Inilah mengapa kita belajar argumen — agar skrip menjadi bahan yang dapat digunakan ulang (reusable), bukan barang sekali pakai.

Positional Parameters: $1, $2, $3, ..., ${10}

Bash menandai argumen pertama sebagai $1, argumen kedua $2, ketiga $3, dan seterusnya. Mereka disebut positional parameters karena posisinya dalam perintah menentukan nilainya. Jalankan skrip berikut dengan beberapa argumen:

skrip_cerita.sh — memakai $1 sampai $3
#!/usr/bin/env bash
echo "Aksi     : $1"
echo "Objek    : $2"
echo "Lokasi   : $3"
Menjalankan dengan 3 argumen
./skrip_cerita.sh install nginx server-01
Output
Aksi     : install
Objek    : nginx
Lokasi   : server-01

Setiap argumen dipisahkan oleh whitespace saat kalian mengetik. Jika satu argumen mengandung spasi (misalnya My Documents), kalian harus membungkusnya dengan tanda kutip: ./skrip_cerita.sh install "My App" server-01 — sehingga "My App" dihitung sebagai satu argumen, bukan dua. Ingat pelajaran quoting di episode 4: kutip adalah cara kita "menempelkan" beberapa kata menjadi satu.

Jebakan Argumen ke-10: ${10}, bukan $10

Ini salah satu jebakan paling klasik dan paling sulit dilacak. Untuk argumen ke-10 ke atas, kalian wajib memakai kurung kurawal: ${10}, ${11}, dan seterusnya. Kenapa? Karena $10 dibaca bash sebagai $1 yang diikuti karakter literal 0. Coba lihat:

skrip_dengan_banyak_argumen.sh
#!/usr/bin/env bash
echo "Argumen ke-1  : $1"
echo "Argumen ke-10 : ${10}"
Jalankan dengan 10 argumen
./skrip_dengan_banyak_argumen.sh a b c d e f g h i J
Output
Argumen ke-1  : a
Argumen ke-10 : J

Sekarang bayangkan kalau kita salah menulis $10:

echo "Argumen ke-10 : $10"
echo "Argumen ke-11 : $11"
Output yang salah (BEFORE)
Argumen ke-10 : a0

Bash menampilkan nilai $1 (yaitu a) lalu menambahkan karakter 0 di belakangnya — tanpa error sama sekali. Inilah jenis bug yang paling berbahaya: gagal secara diam-diam (silent failure). Kalian melihat output "a0", tidak ada pesan error, dan mungkin membuang waktu berjam-jam mencarinya. Selalu gunakan ${10} ke atas, dan biasakan memakai kurung kurawal untuk semua positional parameter — aman dan konsisten.

Special Parameters: $0, $#, $@, $*, $$, $?

Selain positional parameters, bash menyediakan kumpulan parameter khusus yang ditandai simbol tunggal. Mereka bukan argumen, melainkan "metadata" yang diberikan bash kepada setiap skrip:

ParameterArtiContoh Penggunaan
$0Nama skrip yang sedang dijalankanMenampilkan nama skrip dalam pesan error/usage
$#Jumlah argumen (bukan nilainya)if [ $# -eq 0 ]; then → cek tanpa argumen
$@Semua argumen sebagai kata terpisahfor arg in "$@"; do → loop per argumen
$*Semua argumen sebagai satu string"$*" → gabungkan semua argumen dengan spasi
$$PID (Process ID) dari skrip iniMembuat nama file temp unik: /tmp/script_$$.log
$?Exit status perintah terakhircommand; if [ $? -eq 0 ]; then ...

$0 — Nama Skrip

$0 menyimpan nama skrip yang sedang berjalan. Ini berguna untuk dua hal: (1) menampilkan pesan usage yang benar saat argumen salah, dan (2) membuat pesan error yang jelas. Perhatikan pola ini di hampir semua skrip profesional:

Menampilkan usage memakai $0
#!/usr/bin/env bash
if [ $# -lt 2 ]; then
    echo "Usage: $0 <nama> <npm>" >&2
    exit 1
fi

$# — Jumlah Argumen

$# menghitung berapa banyak argumen yang diberikan, bukan nilainya. Jika ./skrip.sh a b c, maka $# bernilai 3. Ini adalah alat validasi nomor satu: sebelum memakai $1, $2, cek dulu bahwa $# cukup. Mengapa? Karena membaca $1 yang tidak ada akan menghasilkan string kosong — skrip terus berjalan tanpa error, tetapi dengan data kosong.

$? — Exit Status Perintah Terakhir

Setiap perintah di bash meninggalkan exit status: 0 berarti sukses, selain 0 (biasanya 1-255) berarti gagal. $? selalu berisi exit status dari perintah yang terakhir dijalankan. Ini adalah bahasa yang dipakai Linux untuk berkomunikasi dengan skrip: apakah pekerjaanmu berhasil?

Memeriksa keberhasilan perintah lewat $?
ls /tmp/siap-produksi
echo "Exit status: $?"
Output
ls: cannot access '/tmp/siap-produksi': No such file or directory
Exit status: 2

Perhatikan: karena ls gagal, exit status-nya bukan 0. Di episode 9 nanti kita akan membahas bagaimana pola ini menjadi jantung dari seluruh logika if di bash. Tapi satu hal wajib diingat sejak sekarang: semua di bash adalah soal exit status.

$$ — PID dari Skrip

$$ berisi Process ID dari proses yang menjalankan skrip. PID adalah identitas unik setiap proses di Linux (ingat konsep /proc di series Linux). Untuk apa berguna? Membuat nama file sementara yang unik:

File temp unik per proses
log_tmp="/tmp/install_$$.log"
echo "Logging ke $log_tmp"
Output
Logging ke /tmp/install_12345.log

Karena setiap proses punya PID berbeda, dua skrip yang berjalan bersamaan tidak akan saling menimpa file temp — analog dengan dua pasien di rumah sakit yang punya nomor rekam medis berbeda, sehingga berkas mereka tidak pernah tertukar.

$@ vs $*: Perbedaan yang Menentukan Hidup-Mati

Dua parameter ini sama-sama merepresentasikan "semua argumen", tetapi perilakunya berbeda drastis — dan inilah salah satu sumber bug paling sering di bash. Ingat aturan emasnya:

  • "$@" — setiap argumen tetap menjadi kata terpisah. Spasi di dalam satu argumen dipertahankan.
  • "$*" — semua argumen digabung menjadi satu string, dipisahkan spasi (karakter pertama dari IFS).

Perhatikan perbedaannya dengan sebuah eksperimen. Buat skrip yang mencetak setiap argumen dalam tanda kurung, agar kita bisa melihat batas antar argumen:

show_args.sh — membandingkan
#!/usr/bin/env bash
echo "Dengan \"\$@\":"
for arg in "$@"; do
    echo "  [\$arg]"
done
 
echo "Dengan \"\$*\":"
for arg in "$*"; do
    echo "  [\$arg]"
done
Jalankan dengan dua argumen yang mengandung spasi
./show_args.sh "file penting.txt" "laporan 2026"
Output
Dengan "$@":
  [file penting.txt]
  [laporan 2026]
Dengan "$*":
  [file penting.txt laporan 2026]

Perhatikan baris terakhir: "$*" menyatukan kedua argumen menjadi satu kata. Bagi loop for, hasilnya cuma satu iterasi — padahal kalian ingin dua file diproses. Kesimpulan praktis: selalu gunakan "$@" untuk "meneruskan semua argumen". "$*" jarang dibutuhkan — hanya saat kalian memang ingin menggabungkan argumen menjadi satu string (misalnya untuk pesan log).

Tip

Cara cepat mengingat perbedaannya: "$@" mempertahankan batas antar argumen, sedangkan "$*" menghapus semua batas. Bayangkan "$@" sebagai lima kantong belanja terpisah yang dibawa pulang — isinya tidak tercampur — sementara "$*" menuangkan semuanya ke satu keranjang besar. Jika kalian meneruskan argumen antar skrip atau ke for loop, kalian hampir selalu butuh kantong-kantong terpisah: "$@".

Apa yang Terjadi Tanpa Tanda Kutip?

Ada kombinasi yang lebih berbahaya lagi: $@ dan $* tanpa tanda kutip. Tanpa kutip, word splitting berlaku (ingat episode 4): setiap argumen akan dipecah ulang berdasarkan spasi. Argumen "file penting.txt" yang tadinya utuh akan dipecah menjadi file, penting.txt, dan txt. Inilah kenapa for f in $@; do dianggap code smell — gunakan for f in "$@"; do.

Important

Aturan yang tidak bisa ditawar: selalu tulis "$@" — dengan tanda kutip. Saat kalian meneruskan argumen ke perintah lain (misalnya script_kedua.sh "$@"), cara inilah yang menjaga setiap argumen tetap utuh apa pun isinya, termasuk spasi dan karakter aneh. Skrip yang menulis $@ tanpa kutip akan hancur begitu menerima nama file yang mengandung spasi — dan di dunia nyata, nama file ber-spasi itu sangat umum.

shift: Mengonsumsi Argumen Secara Berurutan

Kadang kalian tidak tahu berapa banyak argumen yang akan datang, atau ingin memprosesnya satu per satu dari depan. Di sinilah shift berperan: shift membuang $1, lalu menggeser semua argumen satu posisi ke kiri. $2 menjadi $1, $3 menjadi $2, dan $# berkurang satu.

Mengonsumsi argumen satu per satu dengan shift
#!/usr/bin/env bash
while [ $# -gt 0 ]; do
    echo "Memproses: $1"
    shift
done
echo "Semua argumen selesai diproses."
Jalankan
./proses.sh api server web
Output
Memproses: api
Memproses: server
Memproses: web
Semua argumen selesai diproses.

Mengapa pola ini begitu penting? Karena memungkinkan skrip memproses jumlah argumen tak terbatas tanpa harus menulis $1 sampai $100. Analoginya seperti kasir yang melayani antrean pembeli: selama antrean masih ada ($# -gt 0), ia melayani pembeli paling depan ($1), lalu pembeli berikutnya maju (shift). Di episode yang membahas getopts nanti, pola ini akan menjadi fondasi untuk membuat CLI profesional.

Perhatikan juga kondisi loop di atas: [ $# -gt 0 ]. Ini adalah test — kita baru akan mempelajari test operator secara mendalam di episode 9, tapi untuk sekarang cukup pahami bahwa pernyataan itu berbunyi "selama jumlah argumen masih lebih besar dari nol, lanjutkan".

Praktik: Skrip Greet dengan Validasi Argumen

Saatnya merangkai semuanya. Kita akan membangun skrip kecil yang menyapa user, memvalidasi jumlah dan format argumen, serta memanfaatkan $0 untuk pesan usage yang jelas:

greet.sh — validasi argumen lengkap
#!/usr/bin/env bash
set -euo pipefail
 
if [ $# -ne 2 ]; then
    echo "Usage: $0 <nama> <npm>" >&2
    exit 1
fi
 
nama="$1"
npm="$2"
 
echo "Halo, $nama!"
echo "Selamat datang di sesi latihan NPM $npm."
Skrip dengan shebang, validasi, dan output rapi

Mari bedah baris per baris:

BarisYang TerjadiMengapa
#!/usr/bin/env bashShebang — menunjuk interpreter bashSkrip dijalankan dengan bash, bukan shell lain
set -euo pipefailStrict mode: berhenti saat error, variabel kosong, pipeline gagalMencegah skrip "melanjutkan" saat sudah salah — dibahas mendalam di episode error handling
[ $# -ne 2 ]Test: jumlah argumen tidak sama dengan 2Jika user lupa argumen, jangan lanjut — beri tahu cara pakai
$0 <nama> <npm>Pesan usage memakai nama skrip yang sebenarnyaUser tahu persis perintah apa yang harus ia ketik
>&2Redirect pesan ke stderrPesan error harus ke stderr, bukan stdout — agar bisa dipisahkan saat di-pipe
exit 1Hentikan skrip dengan exit status gagalPenelepon skrip (misal CI) tahu bahwa skrip gagal
Uji berbagai kasus
./greet.sh
./greet.sh Arman
./greet.sh Arman 202601001
Output
Usage: ./greet.sh <nama> <npm>
Usage: ./greet.sh <nama> <npm>
Halo, Arman!
Selamat datang di sesi latihan NPM 202601001.

Perhatikan bahwa ./greet.sh dan ./greet.sh Arman menghasilkan pesan usage — karena keduanya tidak memberi dua argumen yang dijanjikan. Skrip yang baik menolak bekerja dengan data tidak lengkap, dan memberikan petunjuk yang jelas. Ini kebiasaan yang akan sangat dihargai saat skrip kalian dipakai orang lain (termasuk "diri kalian enam bulan kemudian").

Common Pitfalls: Jebakan Argument yang Paling Sering Terjadi

1. Membaca $10 alih-alih ${10}

Sudah dibahas di atas, tapi layak diulang sebagai peringatan nomor satu: $10 adalah $1 + 0. Skrip tidak error, tapi outputnya salah total. Selalu gunakan ${10} dan seterusnya.

2. $@ tanpa tanda kutip

for f in $@ akan memecah argumen ber-spasi menjadi potongan-potongan. Di mesin produksi yang penuh nama file seperti hasil_rekap 2026.xlsx, ini adalah bencana. Tulis selalu "$@".

3. Off-by-one dalam loop dengan shift

Pola while [ $# -gt 0 ]; do ...; shift; done sudah benar karena kondisi dicek sebelum setiap iterasi. Kesalahan umum adalah memindahkan shift ke akhir tanpa kondisi yang tepat — atau menulis while [ $# -ge 0 ], yang membuat loop berjalan sekali lagi ketika $# sudah 0, sehingga $1 menjadi kosong. Ingat: gunakan -gt 0, bukan -ge 0.

4. Mengabaikan $# sebelum membaca $1

Membaca $1 saat tidak ada argumen menghasilkan string kosong — skrip berjalan "normal" dengan data kosong, dan error baru muncul jauh di tengah proses (misalnya saat membuat file kosong). Selalu validasi $# lebih dulu. Mencegah lebih mudah daripada mendeteksi.

5. Melupakan exit 1 setelah pesan usage

Jika skrip menampilkan pesan usage lalu melanjutkan bekerja dengan argumen yang hilang, itu lebih buruk daripada tidak memvalidasi sama sekali. Selalu akhiri jalur validasi gagal dengan exit 1 (atau status non-nol yang sesuai).

Penutup

Pada episode 5 ini, kita telah mempelajari bagaimana skrip menerima perintah dari dunia luar: positional parameters $1, $2, hingga ${10} yang membedakan posisi argumen; special parameters $0 (nama skrip), $# (jumlah argumen), $? (exit status terakhir), $$ (PID), serta perbedaan krusial "$@" vs "$*"; dan shift untuk mengonsumsi argumen secara berurutan. Semua itu kita rangkai menjadi skrip greet.sh yang memvalidasi argumennya sendiri.

Inti yang harus dibawa pulang:

  • Argumen adalah cara membuat skrip reusable — data masuk dari luar, bukan di-hardcode.
  • ${10} ke atas wajib memakai kurung kurawal; $10 adalah bug tersembunyi.
  • "$@" menjaga setiap argumen tetap utuh; "$*" menggabungkannya — selalu pilih "$@".
  • $? adalah bahasa komunikasi antara perintah dan skrip: 0 = sukses.
  • Validasi $# sebelum membaca argumen, dan akhiri kegagalan dengan exit 1.

Namun, skrip yang menerima perintah dari command line hanya satu pintu masuk data. Ada pintu lain yang tidak kalah penting: input dari user secara interaktif. Di episode 6 selanjutnya, kita akan membahas User Input Interaktif & Menu dengan read — menguasai perintah read beserta flag -p, -s, -t, -n, -a, membangun menu interaktif dengan select, hingga pola validasi input yang kebal terhadap input kosong dan salah format. Sampai jumpa di episode berikutnya!

Belajar BASH Scripting - Command Line Arguments & Special Parameters | Belajar BASH Scripting