Membangun skrip yang berkomunikasi dua arah dengan user: menguasai perintah read dengan flag -p, -s, -t, -n, -a, membangun menu interaktif dengan select, hingga pola validasi input yang kebal terhadap input kosong, salah format, dan konfirmasi password.

Setelah di episode 5 sebelumnya kita membahas command line arguments & special parameters — bagaimana skrip menerima data lewat $1, $2, $@, hingga $# — pada episode kali ini kita membuka pintu komunikasi kedua: input langsung dari user saat skrip sedang berjalan.
Argumen baris perintah cocok untuk data yang sudah diketahui sebelum skrip dijalankan. Tapi bagaimana jika datanya hanya diketahui saat skrip berjalan — misalnya nama user, pilihan menu, atau password? Menuntut semua itu lewat argumen akan membuat baris perintah kalian panjang dan kaku. Jawabannya adalah perintah read, yang membuat skrip berhenti sejenak, bertanya, dan menyimpan jawabannya ke dalam variabel. Inilah yang membedakan skrip bisu yang hanya menerima perintah dengan skrip interaktif yang bisa "berdialog" dengan penggunanya.
read: Mendengarkan Apa yang User KetikPerintah read membaca satu baris input dari keyboard (atau dari file/pipe) dan menyimpannya ke variabel. Contoh paling sederhana:
#!/usr/bin/env bash
read nama
echo "Halo, $nama!"./read_sederhana.shArman
Halo, Arman!Tidak ada prompt sama sekali — kursor hanya berhenti berkedip menunggu. User pemula akan bingung "saya harus ketik apa?". Inilah mengapa kita butuh flag -p: untuk memberi tahu user apa yang diminta sebelum mereka mengetik.
read -p — Menampilkan Prompt#!/usr/bin/env bash
read -p "Siapa nama kamu? " nama
echo "Senang bertemu, $nama!"Siapa nama kamu? Arman
Senang bertemu, Arman!-p menampilkan teks prompt sebelum membaca input. Perhatikan spasi di akhir prompt (? ) — tanpa spasi, apa yang diketik user akan "menempel" langsung di akhir tanda tanya. Detail kecil seperti ini yang membuat skrip terasa profesional.
read -s — Silent Mode untuk PasswordSaat user mengetik password, kita tidak ingin karakternya terlihat di layar (orang di belakang bisa mengintip, dan riwayat layar iklan tidak membantu). Flag -s membuat input tidak ditampilkan — namun tetap tersimpan di variabel:
#!/usr/bin/env bash
read -s -p "Masukkan password: " password
echo
echo "Password diterima (${#password} karakter)."Masukkan password: ••••••••
Password diterima (8 karakter).Ada dua detail penting di sini. Pertama, -s tidak menampilkan input — kursor tetap berhenti, dan setiap ketukan tidak muncul. Kedua, perhatikan echo kosong di baris setelah read: karena read -s tidak menghasilkan baris baru setelah user menekan Enter (mirip echo -n), tanpa echo tambahan, prompt berikutnya akan muncul di baris yang sama dengan input yang tersembunyi. Baris kosong ini "menutup" baris tersebut.
Important
read -s menyembunyikan tampilan, bukan mengamankan data. Password tetap tersimpan dalam variabel (terlihat oleh proses lain yang bisa membaca memori) dan bisa bocor ke shell history jika kalian menulisnya sebagai argumen. read -s bukan pengganti manajemen secret yang layak — ia hanya mencegah shoulder surfing. Untuk secret sungguhan, gunakan tools seperti Vault, yang akan kita bahas di series lain.
read -t — Timeout: Jangan Membiarkan Skrip Menunggu SelamanyaDi otomasi (cron job, CI/CD), skrip yang menunggu input selamanya adalah bencana — pipeline akan menggantung tanpa batas. Flag -t membatasi waktu tunggu dalam detik:
#!/usr/bin/env bash
if read -t 5 -p "Konfirmasi deploy (y/n): " jawaban; then
echo "Jawaban: $jawaban"
else
echo
echo "Tidak ada jawaban dalam 5 detik — membatalkan deploy."
exit 1
fiYang menarik: read sendiri mengembalikan exit status. Jika user menjawab sebelum timeout, read sukses (exit status 0); jika timeout habis, read gagal (exit status non-nol). Karena itu kita bisa langsung memakai if read ... sebagai kondisinya — ini memanfaatkan pelajaran $? dari episode 5 secara elegan. Pola ini ideal untuk skrip otomasi yang harus batal sendiri jika tidak ada manusia yang mengoperasikan.
read -n — Membaca Sejumlah Karakter (Tombol Tunggal)Kadang kita hanya butuh satu karakter — seperti jawaban "y" atau "n". Flag -n 1 membuat read berhenti setelah satu karakter, tanpa menunggu Enter:
#!/usr/bin/env bash
read -n 1 -p "Hapus cache? (y/N) " jawaban
echo
case "$jawaban" in
y|Y) echo "Menghapus cache...";;
*) echo "Dibatalkan.";;
esacHapus cache? (y/N) y
Menghapus cache...Perhatikan pola (y/N) dengan N kapital — konvensi Unix yang berarti "default-nya adalah Tidak". User tinggal menekan satu tombol, tanpa perlu Enter. Ini terasa ringan dan cepat, persis seperti cara aplikasi installer berinteraksi dengan user.
read -a — Membaca ke Dalam ArrayFlag -a membaca seluruh baris input dan memecahnya menjadi elemen array berdasarkan spasi (IFS). Sangat berguna untuk menerima daftar nilai dalam satu prompt:
#!/usr/bin/env bash
read -a packages -p "Daftar paket (pisahkan spasi): "
for pkg in "${packages[@]}"; do
echo " - $pkg"
doneDaftar paket (pisahkan spasi): nginx redis postgres
- nginx
- redis
- postgresKita akan membahas array secara mendalam di episode yang membahas array indexed & assosiatif. Untuk sekarang, cukup pahami bahwa read -a nama_array adalah cara singkat mengubah satu baris input menjadi daftar elemen yang bisa di-loop.
read| Flag | Fungsi | Kapan Digunakan |
|---|---|---|
-p "teks" | Menampilkan prompt sebelum membaca | Hampir selalu — user harus tahu apa yang diminta |
-s | Tidak menampilkan input (mode senyap) | Password, token, input sensitif |
-t N | Timeout N detik; read gagal jika habis | Skrip otomasi yang harus batal sendiri |
-n N | Berhenti setelah N karakter (tanpa Enter) | Konfirmasi satu tombol y/n |
-a arr | Simpan input sebagai array (pecah spasi) | Menerima daftar nilai dalam satu prompt |
-r | Jangan perlakukan \ sebagai escape | Hampir selalu — mencegah backslash hilang |
Tip
Biasakan selalu menulis read -r bersama flag lainnya (misal read -rp "Nama: " nama). Tanpa -r, bash menganggap backslash sebagai karakter escape — jadi path Windows seperti C:\Users\Arman akan kehilangan \U, \A. Aturan praktis: jika kalian tidak tahu kenapa butuh flag -r, kalian tetap butuh -r.
Hukum pertama pemrograman interaktif: input dari user tidak bisa dipercaya. User bisa menekan Enter tanpa mengetik apa pun, mengetik angka padahal diminta teks, atau mengetik format yang salah. Skrip yang baik memvalidasi, dan jika input buruk, bertanya lagi — bukan meneruskan dengan data yang salah.
Pola paling dasar: loop sampai user memberikan jawaban yang tidak kosong. Kuncinya adalah loop — validasi satu kali tidak cukup, karena user bisa memberi input buruk berkali-kali.
#!/usr/bin/env bash
while [ -z "$nama" ]; do
read -rp "Nama project (wajib): " nama
if [ -z "$nama" ]; then
echo "Nama tidak boleh kosong. Coba lagi."
fi
done
echo "Project: $nama"Loop terus berjalan selama $nama masih kosong. -z "$nama" berarti "benar jika string kosong" — kita akan mempelajari test operator ini lebih dalam di episode 9. Untuk sekarang, pahami polanya: cek → jika salah, beri tahu → ulangi. Ini adalah siklus validasi universal.
Validasi kosong hanya menyaring ketiadaan input. Untuk memastikan bentuknya, gunakan pola regex — bash punya operator =~ yang baru kita kenalkan di sini secara singkat:
#!/usr/bin/env bash
while ! [[ "$npm" =~ ^[0-9]{9}$ ]]; do
read -rp "NPM (9 digit angka): " npm
[[ "$npm" =~ ^[0-9]{9}$ ]] || echo "Format salah — harus 9 digit angka."
done
echo "NPM valid: $npm"Pola ^[0-9]{9}$ dibaca: mulai dari awal, sembilan digit angka, lalu berakhir — artinya seluruh string harus persis 9 digit angka, tidak lebih tidak kurang. Di episode 9 kita akan membedah [[ ]] dan regex ini lebih detail. Yang penting sekarang: format validasi adalah garis pertahanan kedua setelah cek kosong.
Untuk password, standar praktik adalah memasukkan dua kali dan membandingkan — mencegah typo yang tidak terlihat karena inputnya tersembunyi. Gabungkan dengan -s dan loop:
#!/usr/bin/env bash
while true; do
read -s -p "Buat password: " pw1
echo
read -s -p "Ulangi password: " pw2
echo
if [ -z "$pw1" ]; then
echo "Password tidak boleh kosong."
elif [ "$pw1" != "$pw2" ]; then
echo "Password tidak cocok — coba lagi."
else
break
fi
done
echo "Password berhasil disimpan."Mengapa konfirmasi ganda? Karena di layar yang senyap, typo tidak terlihat — user bisa "yakin" sudah mengetik dengan benar padahal salah. Konfirmasi kedua adalah jaring pengaman yang harganya murah tapi menyelamatkan dari masalah besar di kemudian hari (misalnya akun terkunci karena password yang salah saat deploy).
selectMembangun menu dengan read + case (seperti di contoh -n 1 di atas) memungkinkan, tapi bash menyediakan alat yang lebih nyaman: loop select. Ia otomatis menampilkan nomor menu, menerima pilihan, dan menyimpannya ke variabel. Ini sangat cocok untuk skrip yang menawarkan pilihan terbatas — persis seperti menu di aplikasi layanan mandiri.
#!/usr/bin/env bash
PS3="Pilih opsi (1-3): "
select opsi in "Cek status" "Tampilkan log" "Keluar"; do
case "$opsi" in
"Cek status") echo "→ Menjalankan status check...";;
"Tampilkan log") echo "→ Menampilkan log terakhir...";;
"Keluar") echo "Sampai jumpa!"; break;;
*) echo "Opsi tidak valid.";;
esac
done1) Cek status
2) Tampilkan log
3) Keluar
Pilih opsi (1-3): 2
→ Menampilkan log terakhir...
Pilih opsi (1-3): 3
Sampai jumpa!Dua hal yang perlu diperhatikan:
PS3 adalah prompt khusus select. Tanpa mengatur PS3, prompt default-nya adalah #? yang membingungkan user. Aturan praktis: selalu set PS3 — ini pertanyaan paling umum di skrip select.select akan terus menampilkan menu lagi setelah setiap pilihan. Untuk keluar, kita perlu break (atau exit). Tanpa break, user akan terjebak dalam menu selamanya.Warning
Tolak mentah-mentah input menu yang tidak valid. select menerima nomor pilihan, bukan teks — jika user mengetik huruf, $opsi menjadi kosong dan case masuk ke cabang *. Pastikan selalu ada cabang *) sebagai jaring pengaman, persis seperti pada contoh di atas. Menu tanpa cabang * akan "diam" tanpa penjelasan saat user mengetik angka di luar rentang — perilaku yang membingungkan.
Mari kita rangkai semuanya menjadi satu skrip yang realistis: menu maintenance yang menerima password dengan konfirmasi, memvalidasi input, dan menawarkan aksi-aksi berbeda:
#!/usr/bin/env bash
set -euo pipefail
# 1. Konfirmasi password (dua kali, cocok, tidak kosong)
while true; do
read -s -p "Buat password maintenance: " pw1; echo
read -s -p "Ulangi password: " pw2; echo
if [ -z "$pw1" ]; then
echo "Password tidak boleh kosong."
elif [ "$pw1" != "$pw2" ]; then
echo "Tidak cocok — coba lagi."
else
echo "Password diterima."
break
fi
done
# 2. Minta nama target dengan validasi
while [ -z "$server" ]; do
read -rp "Nama server target: " server
done
# 3. Menu aksi
PS3="Aksi untuk $server: "
select aksi in "Status" "Restart" "Keluar"; do
case "$aksi" in
"Status") echo "→ Mengecek status $server...";;
"Restart") echo "→ Me-restart $server...";;
"Keluar") echo "Selesai."; break;;
*) echo "Pilihan tidak valid.";;
esac
doneMari bedah alurnya — ini contoh nyata bagaimana ketiga pola bekerja sama:
| Tahap | Pola | Alasan |
|---|---|---|
| 1 | Konfirmasi password (read -s dua kali + banding) | Mencegah typo pada input tersembunyi |
| 2 | Validasi non-kosong (while [ -z ] + re-prompt) | Nama server tidak boleh kosong |
| 3 | Menu select + PS3 + cabang * + break | Navigasi aksi yang aman dan bisa keluar |
Skrip ini sekarang bisa dijalankan di terminal tanpa argumen — semua data diperoleh lewat dialog. Bandingkan dengan skrip di episode 5 yang semuanya lewat argumen. Keduanya sah — yang mana yang dipakai bergantung konteks: argumen untuk data yang diketahui sebelumnya dan bisa di-otomasi; read/select untuk data yang hanya bisa diberikan manusia saat berinteraksi.
read di dalam pipe → variabel hilangIni jebakan paling klasik dan paling membingungkan:
echo "Arman" | read nama
echo "Halo, $nama" # KOSONG!Kenapa terjadi? Setiap sisi pipeline | dijalankan dalam subshell — proses terpisah. read membaca input di subshell itu, dan variabelnya mati bersama subshell saat pipeline selesai. Variabel nama di shell utama tidak pernah tersentuh. Solusinya: baca langsung dari file (< file), pakai process substitution (< <(cmd)), atau — jika memungkinkan — baca dari while loop di dalam konstruksi yang sama. Selama kalian menulis ... | while read, ingat: variabel di dalam loop itu tidak akan keluar dari loop.
Di cron job atau CI/CD, tidak ada manusia yang menunggu di depan terminal. Jika skrip memanggil read tanpa -t, dan stdin tidak menyediakan data, skrip akan menggantung selamanya dan pipeline berhenti total. Selalu tanya: apakah skrip ini akan dijalankan tanpa manusia? Jika ya, gunakan read -t N dan siapkan jalur default (seperti contoh read -t di atas yang membatalkan deploy).
PS3 tidak di-set → prompt #? select yang tidak menetapkan PS3 menampilkan #? yang misterius. User tidak tahu harus mengetik apa. Set PS3 setiap kali menggunakan select.
echo setelah read -sread -s tidak mencetak baris baru setelah Enter. Prompt berikutnya akan menempel di baris yang sama dengan input tersembunyi — terlihat seperti skrip "hang". Tambahkan echo setelahnya.
"..."[ "$pw1" != "$pw2" ] dengan tanda kutip itu benar. Tanpa tanda kutip — [ $pw1 != $pw2 ] — password yang berisi spasi akan dipecah menjadi beberapa kata dan error "unary operator expected". Kutip selalu. Detail ini dibahas tuntas di episode 9.
Pada episode 6 ini, kita telah mengubah skrip dari alat bisu menjadi alat yang bisa berdialog: perintah read dengan flag -p (prompt), -s (senyap untuk password), -t (timeout), -n (jumlah karakter), dan -a (array); pola validasi input yang kebal terhadap input kosong dan format salah dengan siklus re-prompt; pola konfirmasi password dua kali; serta menu interaktif dengan select dan PS3.
Inti yang harus dibawa pulang:
read -rp untuk prompt yang jelas, dan selalu -r untuk mencegah backslash hilang.read -s untuk password — tapi ingat, ini menyembunyikan tampilan, bukan mengamankan.read -t wajib di skrip otomasi agar tidak menggantung.select + PS3 + cabang * + break adalah resep menu yang aman.| while read — variabel tidak akan keluar dari subshell.Setelah kalian bisa menerima data dari command line dan dari user interaktif, ada satu domain data lain yang sering dilupakan: file-file di filesystem. Bagaimana cara mengambil daftar file yang cocok dengan pola tertentu — *.log, report_2026*, semua file .png? Di episode 7 selanjutnya, kita akan membahas Globbing & Pathname Expansion — wildcard *, ?, [...], brace expansion, hingga globstar **, plus mengapa kita harus selalu memakai glob dan tidak pernah mem-parse output ls. Sampai jumpa!