Input, Output, dan Redirection

Input, Output, dan Redirection

Bitnesia • Aug 30, 2026 73 •EN

Setiap script yang dibahas sejak Bab 1 sampai Bab 4 masih berjalan satu arah: kita menulis logikanya, lalu hasilnya muncul begitu saja di layar tanpa ada interaksi dengan orang yang menjalankannya. Kenyataannya, script yang berguna hampir selalu perlu berkomunikasi dua arah, baik itu menerima input lewat keyboard, menampilkan hasil yang rapi dan mudah dibaca, memisahkan pesan error dari output normal, maupun menyimpan hasil eksekusi ke dalam file log untuk diperiksa Sysadmin nanti. Bab ini membahas tiga builtin utama untuk interaksi dasar (echo, printf, dan read), konsep tiga saluran data bawaan setiap proses (stdin, stdout, stderr), teknik redirection untuk mengarahkan saluran-saluran itu ke file, dan pipe untuk menyambungkan output satu perintah menjadi input perintah berikutnya, ditutup dengan studi kasus yang menggabungkan semuanya dalam satu script siap pakai.

5.1 echo, printf, dan read untuk Interaksi dengan User

Sub-bab ini membahas tiga builtin yang paling sering dipakai untuk berkomunikasi dengan orang yang menjalankan script, yaitu echo dan printf untuk menampilkan pesan, serta read untuk menangkap input yang diketik.

5.1.1 Menampilkan Teks dengan echo

echo adalah builtin paling sederhana untuk menampilkan teks ke layar. Perintah ini sudah sering muncul di bab-bab sebelumnya tanpa dibahas detailnya.

echo "Setup server dimulai"

Secara default, Bash tidak menafsirkan karakter escape seperti \n atau \t di dalam argumen echo, keduanya hanya ditampilkan apa adanya sebagai teks literal. Ini poin yang sering bikin bingung pemula yang terbiasa dengan bahasa lain.

echo "Baris satu\nBaris dua"

Baris di atas menampilkan Baris satu\nBaris dua persis seperti tertulis, bukan dua baris terpisah, karena Bash memperlakukan \n sebagai dua karakter biasa.

5.1.2 Opsi -n dan -e pada echo

Dua opsi echo yang paling sering dipakai adalah -n untuk menghilangkan newline di akhir output, dan -e untuk mengaktifkan interpretasi karakter escape yang sebelumnya diabaikan.

echo -n "Memeriksa koneksi... "
echo -e "Status:\n- OK\n- Siap dipakai"

echo -n berguna saat kita ingin menampilkan indikator progres tanpa langsung pindah ke baris baru, sedangkan echo -e mengaktifkan escape sequence seperti \n (baris baru), \t (tab), dan \\ (backslash literal). Perlu dicatat, perilaku default echo tanpa -e ini spesifik untuk Bash; beberapa shell lain seperti sh pada beberapa sistem justru menafsirkan escape secara default, jadi jangan mengasumsikan perilaku yang sama persis saat script dijalankan lewat shell selain Bash.

5.1.3 Format Presisi dengan printf

printf adalah builtin yang lebih tepat digunakan saat kita butuh kontrol format output yang presisi, misalnya menyelaraskan kolom angka atau memaksa jumlah digit desimal tertentu. Sintaksnya mengikuti pola format string yang sudah dikenal luas dari bahasa C: format diikuti daftar argumen yang mengisi setiap penanda format (format specifier).

printf "Nama: %s, Umur: %d tahun\n" "Budi" 30

Penanda %s menyisipkan string, %d menyisipkan angka bulat, dan %f menyisipkan angka desimal. Berbeda dari echo, printf tidak pernah menambahkan newline secara otomatis di akhir output, jadi \n harus dituliskan secara eksplisit jika dibutuhkan.

printf "Disk terpakai: %.1f%%\n" 78.456

Baris di atas menampilkan Disk terpakai: 78.5%, karena %.1f membulatkan angka desimal menjadi satu digit di belakang koma, dan %% dipakai untuk menampilkan karakter persen literal karena tanda persen tunggal punya arti khusus dalam format string. Satu keunggulan printf yang jarang disadari pemula: jika argumen yang diberikan lebih banyak daripada jumlah penanda format, printf otomatis mengulang format string sampai semua argumen habis diproses, sangat berguna untuk mencetak data berulang dengan struktur seragam.

printf "%s: %s\n" "web1" "aktif" "db1" "nonaktif"

5.1.4 Membaca Input User dengan read

read adalah builtin untuk menangkap satu baris input dari stdin, biasanya dari keyboard, lalu menyimpannya ke dalam variabel. Konsep stdin sendiri akan dibahas lebih detail di sub-bab 5.2.

echo "Masukkan nama server:"
read nama_server
echo "Server yang dipilih: $nama_server"

Jika read dipanggil tanpa nama variabel, Bash otomatis menyimpan input ke variabel bawaan bernama REPLY. Jika lebih dari satu nama variabel dituliskan, read membagi input berdasarkan IFS (sama seperti pembahasan word splitting di Bab 3), lalu mengisi setiap variabel sesuai urutannya, dengan sisa kata berlebih otomatis masuk ke variabel terakhir.

read user host
# input: admin server1.example.com
echo "User: $user, Host: $host"

5.1.5 Opsi Penting pada read

Beberapa opsi read berikut ini yang paling sering dipakai di lapangan. Opsi -p menampilkan teks prompt tanpa perlu echo terpisah.

read -p "Masukkan nama server: " nama_server

Perlu diperhatikan, teks prompt dari -p hanya tampil jika stdin memang berasal dari terminal interaktif. Saat script dijalankan lewat pipe atau input dialihkan dari file (topik yang dibahas di sub-bab 5.3), prompt ini tidak akan muncul sama sekali meski read tetap mencoba membaca data seperti biasa.

Opsi -s (silent) menyembunyikan karakter yang diketik dari layar, cocok untuk input sensitif seperti password.

read -sp "Masukkan password database: " db_pass
echo

Baris echo kosong setelah read -s sengaja ditambahkan karena karakter Enter yang ditekan user tidak ikut menghasilkan newline di layar akibat mode silent, sehingga prompt berikutnya bisa menempel di baris yang sama tanpa baris tambahan itu.

Opsi -a menyimpan input ke dalam indexed array yang sudah dibahas di Bab 4, dengan setiap kata hasil split menjadi satu elemen.

read -a daftar_port -p "Masukkan daftar port, pisahkan spasi: "
echo "Port pertama: ${daftar_port[0]}"

Opsi -n membuat read langsung berhenti setelah membaca sejumlah karakter tertentu, tanpa menunggu tombol Enter, cocok untuk konfirmasi cepat gaya "tekan tombol apa saja".

read -n 1 -p "Lanjutkan proses? (y/n) " jawaban
echo

Opsi -t menambahkan batas waktu dalam detik. Jika user tidak mengetik apa pun sampai batas waktu habis, read berhenti dan mengembalikan status gagal, berguna untuk script otomatis yang tidak boleh menunggu input selamanya saat dijalankan tanpa pengawasan, misalnya lewat cron yang akan dibahas di Bab 18.

read -t 10 -p "Ketik sesuatu dalam 10 detik: " respon

5.1.6 Troubleshooting: read Tanpa Opsi -r

Kesalahan yang cukup sering luput dari perhatian adalah memanggil read tanpa opsi -r. Tanpa -r, read memperlakukan backslash sebagai karakter escape, sehingga backslash itu sendiri ikut dihapus dari nilai yang tersimpan, bukan disimpan apa adanya sebagai bagian dari input.

read path
# input yang diketik: C:\Users\budi
echo "$path"
C:Usersbudi

Perhatikan, setiap backslash pada input di atas hilang sepenuhnya dari hasil echo, bukan ikut tersimpan sebagai bagian dari path, karena read memperlakukannya sebagai penanda escape untuk karakter berikutnya. Kebiasaan yang aman dan direkomendasikan ShellCheck adalah selalu menambahkan -r kecuali kita memang sengaja butuh backslash diproses sebagai escape.

read -r path
# input yang diketik: C:\Users\budi
echo "$path"
C:\Users\budi

5.2 Standard Input, Output, dan Error

Setelah memahami cara menampilkan dan menangkap input, sub-bab ini membahas konsep dasar di baliknya: tiga saluran data yang otomatis tersedia untuk setiap proses yang dijalankan di sistem Unix-like, termasuk Linux dan macOS.

5.2.1 Tiga File Descriptor Bawaan

Setiap kali sebuah proses dijalankan, shell secara otomatis menyediakan tiga saluran komunikasi berupa file descriptor, yaitu angka yang menjadi rujukan sistem operasi untuk membaca atau menulis data. Tiga file descriptor ini sudah didefinisikan sesuai standar POSIX dan selalu tersedia tanpa perlu diatur manual.

NomorNamaFungsiTujuan Default
0stdin (standard input)Sumber data masuk untuk perintahKeyboard
1stdout (standard output)Saluran output normalLayar terminal
2stderr (standard error)Saluran pesan errorLayar terminal

Builtin read yang dibahas di sub-bab 5.1 sebenarnya membaca dari stdin (fd 0), sedangkan echo dan printf menulis ke stdout (fd 1). Menariknya, secara visual stdout dan stderr terlihat sama saja karena keduanya sama-sama tampil di layar terminal secara default, padahal keduanya adalah dua saluran yang benar-benar terpisah di level sistem operasi.

5.2.2 Kenapa stderr Dipisah dari stdout

Pemisahan stdout dan stderr bukan tanpa alasan. Tujuannya supaya output normal (data yang memang ingin diproses atau disimpan) tidak tercampur dengan pesan error atau peringatan, yang biasanya hanya perlu diketahui oleh orang yang menjalankan script, bukan ikut masuk ke dalam data hasil. Pola echo "pesan error" >&2 adalah cara umum untuk menulis eksplisit ke stderr dari dalam script, teknik yang sudah lazim dipakai Sysadmin untuk membedakan log error dari log normal.

echo "Memulai backup database..."
echo "Error: kredensial database tidak ditemukan" >&2

Sintaks >&2 ini adalah bentuk redirection yang akan dibahas tuntas di sub-bab 5.3. Kegunaan praktis pemisahan ini akan terlihat jelas saat kita membahas redirection: output normal bisa disimpan ke satu file log, sementara pesan error disimpan ke file terpisah atau langsung ditampilkan ke layar, tanpa saling mengganggu.

5.2.3 Melihat File Descriptor Aktif Sebuah Proses

Di Linux, kita bisa memeriksa file descriptor yang sedang dipakai oleh proses tertentu lewat direktori /proc, bagian dari pseudo-filesystem yang merepresentasikan informasi kernel dan proses secara langsung. Perintah berikut menampilkan file descriptor milik shell yang sedang aktif, memakai $$ yang merujuk PID proses shell saat ini.

ls -l /proc/$$/fd

Output-nya menunjukkan tiga symbolic link bernomor 0, 1, dan 2, masing-masing mengarah ke perangkat terminal yang sedang dipakai. Perlu dicatat, direktori /proc ini spesifik untuk Linux; macOS yang berbasis BSD tidak memiliki filesystem /proc, sehingga pemeriksaan serupa di macOS perlu memakai tool lain seperti lsof -p, topik yang lebih relevan dibahas saat masuk ke manajemen proses di Bab 17.

5.3 Redirection dan Pipe

Sub-bab ini masuk ke bagian inti bab: teknik mengarahkan tiga saluran data dari sub-bab 5.2 ke tujuan lain selain layar dan keyboard, baik itu file maupun perintah lain.

5.3.1 Redirection Output dengan > dan >>

Redirection adalah teknik mengalihkan tujuan sebuah saluran input/output dari perilaku default-nya. Operator > mengalihkan stdout dari sebuah perintah supaya ditulis ke file, bukan ditampilkan ke layar.

echo "Backup selesai pada $(date)" > status.log

Perlu diperhatikan, operator > selalu membuat ulang isi file dari kosong (truncate) jika file sudah ada sebelumnya, sehingga isi lama akan hilang begitu saja tanpa peringatan. Ini salah satu perintah yang berpotensi merusak data jika file tujuan salah ketik, jadi selalu periksa nama file tujuan sebelum menjalankan redirection ke file yang sudah berisi data penting. Untuk menambahkan output ke akhir file tanpa menghapus isi lama, gunakan >> sebagai gantinya.

echo "Backup selesai pada $(date)" >> status.log

Pola >> inilah yang biasa dipakai Sysadmin untuk menulis log secara berkelanjutan, karena setiap eksekusi script menambah baris baru alih-alih menimpa riwayat sebelumnya.

5.3.2 Redirection Input dengan <

Operator < bekerja kebalikan dari >, yaitu mengalihkan sumber stdin sebuah perintah supaya dibaca dari isi file, bukan dari keyboard.

read nama_server < konfigurasi.txt
echo "Server dari file: $nama_server"

Baris di atas membuat read mengambil input dari baris pertama konfigurasi.txt, persis seolah-olah isi baris itu diketik langsung ke terminal.

5.3.3 Redirection stderr dengan 2> dan Gabungan &>

Karena stderr adalah saluran terpisah dengan nomor file descriptor 2, redirection-nya memakai 2>, dengan angka 2 dituliskan langsung menempel di depan tanda lebih besar.

ls /direktori/tidak/ada 2> error.log

Baris di atas tetap menampilkan apa pun yang normal ke layar (jika ada), tapi pesan error dari ls dialihkan ke error.log. Untuk mengalihkan stdout dan stderr sekaligus ke file yang sama, Bash menyediakan operator ringkas &>.

ls /etc /direktori/tidak/ada &> hasil_lengkap.log

Operator &> ini perlu dicatat sebagai fitur khas Bash (dan tersedia juga di beberapa shell lain seperti zsh), bukan bagian dari standar POSIX shell, sehingga tidak akan berfungsi jika script dijalankan lewat sh murni seperti dash di beberapa distro. Untuk kompatibilitas lintas shell yang lebih luas, pola 2>&1 di sub-bab berikutnya adalah alternatif yang lebih portable.

5.3.4 Urutan Redirection dan Pola 2>&1

Pola 2>&1 adalah cara POSIX-compliant untuk menggabungkan stderr ke saluran yang sama dengan stdout. Artinya, "arahkan file descriptor 2 ke tujuan yang sama dengan file descriptor 1 saat ini".

ls /etc /direktori/tidak/ada > hasil_lengkap.log 2>&1

Urutan penulisan di sini sangat menentukan hasilnya, dan ini salah satu jebakan paling umum bagi pemula. Bash memproses redirection dari kiri ke kanan, jadi pada baris di atas, > hasil_lengkap.log dulu yang dieksekusi (mengarahkan stdout ke file), baru kemudian 2>&1 menyalin tujuan itu ke stderr, sehingga keduanya berakhir di file yang sama. Jika urutannya dibalik, hasilnya berbeda total.

ls /etc /direktori/tidak/ada 2>&1 > hasil_lengkap.log

Pada baris ini, 2>&1 dieksekusi lebih dulu saat stdout masih mengarah ke layar terminal, sehingga stderr ikut disalin ke layar terminal. Baru setelah itu > hasil_lengkap.log mengubah tujuan stdout ke file, tapi perubahan ini tidak berlaku surut untuk stderr yang sudah kadung diarahkan ke layar. Akibatnya, pesan error tetap muncul di layar, bukan masuk ke file. Aturan praktis yang mudah diingat: letakkan 2>&1 selalu di posisi paling akhir jika tujuannya menggabungkan stderr ke stdout.

Satu pola lain yang sangat umum ditemui di script otomatis, terutama yang dijadwalkan lewat cron di Bab 18, adalah membuang seluruh output ke perangkat khusus bernama /dev/null, yaitu device file yang membuang semua data yang ditulis ke dalamnya tanpa menyimpan apa pun.

./cek_backup.sh > /dev/null 2>&1

Pola ini membungkam seluruh output script, baik normal maupun error, cocok untuk proses terjadwal yang hasilnya sudah ditangani lewat mekanisme logging tersendiri seperti dibahas di Bab 19, dan tidak butuh output tambahan yang justru memenuhi mailbox sistem.

5.3.5 Pipe | dan tee untuk Menyalurkan Output

Pipe, disimbolkan dengan karakter |, menyambungkan stdout dari satu perintah langsung menjadi stdin perintah berikutnya, tanpa perlu file perantara. Konsep ini berbeda dari redirection yang menghubungkan saluran ke file, pipe menghubungkan langsung dua proses.

ps -eo user= | sort | uniq -c

Baris di atas menyalurkan output ps (daftar proses) sebagai input untuk sort (mengurutkan), lalu hasilnya disalurkan lagi sebagai input uniq -c (menghitung baris yang berurutan dan sama). Rangkaian seperti ini disebut pipeline, dan bisa disambung sepanjang yang dibutuhkan. Satu detail teknis yang penting diketahui: setiap perintah dalam sebuah pipeline dijalankan Bash di dalam subshell-nya masing-masing (proses turunan terpisah), kecuali opsi lastpipe diaktifkan pada kondisi tertentu. Konsekuensinya, variabel yang di-assign di dalam perintah terakhir sebuah pipe (misalnya while read yang menerima data lewat pipe) tidak akan terbawa keluar setelah pipeline selesai, karena assignment itu terjadi di subshell yang terpisah dari shell utama. Ini jebakan klasik yang sering membuat pemula bingung kenapa variabel counter di dalam loop selalu kembali ke nilai awal setelah pipeline berakhir, topik yang akan disinggung lagi saat membahas trap dan debugging di Bab 25.

Perintah tee adalah tool yang berguna dipasangkan dengan pipe ketika kita ingin output tetap tampil di layar sekaligus disimpan ke file, tanpa harus memilih salah satu. tee membaca dari stdin, lalu menuliskannya sekaligus ke stdout dan ke file yang disebutkan sebagai argumen.

echo "Memulai pengecekan disk" | tee status.log
df -h | tee -a status.log

Sama seperti >> pada redirection biasa, opsi -a pada tee membuatnya menambahkan ke akhir file alih-alih menimpa isi lama.

5.3.6 Troubleshooting Redirection Umum

Kesalahan paling umum adalah lupa bahwa > bersifat destruktif dan menimpa file tanpa konfirmasi apa pun. Bash sebenarnya menyediakan opsi set -o noclobber (atau set -C) yang membuat > menolak menimpa file yang sudah ada, sehingga error muncul lebih dulu daripada kehilangan data secara tidak sengaja.

set -o noclobber
echo "test" > status.log
bash: status.log: cannot overwrite existing file

Jika memang sengaja ingin menimpa meski noclobber aktif, tambahkan tanda seru setelah tanda lebih besar, yaitu >|. Kesalahan umum kedua adalah salah kira bahwa redirection 2> error.log saja sudah cukup untuk menangkap semua output, padahal stdout tetap tampil ke layar seperti biasa kecuali dialihkan juga secara terpisah. Kesalahan ketiga, seperti sudah disinggung di sub-bab 5.3.4, adalah salah urutan menuliskan 2>&1 relatif terhadap > file.

5.4 Studi Kasus: Menggabungkan Beberapa Perintah dengan Pipe

Sub-bab penutup ini merangkai read, redirection, dan pipe dalam satu script praktis: laporan ringkas jumlah proses yang sedang berjalan per user di sebuah server, tugas kecil namun nyata yang biasa dilakukan Sysadmin saat memeriksa apakah ada user atau service yang tiba-tiba membuka proses berlebihan.

5.4.1 Skenario dan Rancangan Alur Data

Script akan menanyakan kepada Sysadmin berapa banyak baris teratas yang ingin ditampilkan lewat read -p, lalu menjalankan pipeline ps untuk mengambil daftar user pemilik proses, mengurutkannya, menghitung kemunculan tiap user, mengurutkan ulang dari yang terbanyak, dan pada akhirnya menampilkan hasilnya sekaligus menyimpannya ke file laporan lewat tee. Contoh ini memakai opsi -eo user= yang mengikuti sintaks GNU ps, umum tersedia di distro Linux; pada macOS yang memakai BSD ps, opsi dan flag yang tersedia sedikit berbeda, topik yang dibahas lebih lengkap saat masuk ke manajemen proses di Bab 17.

5.4.2 Menulis Script Lengkap

Simpan script berikut sebagai laporan_proses.sh.

#!/bin/bash

read -rp "Tampilkan berapa banyak user teratas? " jumlah_baris
laporan="laporan_proses_user.txt"

echo "Laporan jumlah proses per user - $(date '+%Y-%m-%d %H:%M:%S')" > "$laporan"
echo "===========================================" >> "$laporan"

ps -eo user= | sort | uniq -c | sort -rn | head -n "$jumlah_baris" | tee -a "$laporan"

echo "Laporan lengkap tersimpan di: $laporan"

Perhatikan bagaimana dua jenis redirection dan satu pipeline panjang dipakai bersamaan di sini. > dipakai sekali di awal untuk memulai file laporan dari kosong, >> menambahkan baris pemisah, lalu seluruh pipeline ps | sort | uniq -c | sort -rn | head mengalirkan data dari satu perintah ke perintah berikutnya sebelum akhirnya tee -a menuliskan hasil akhirnya ke layar sekaligus menambahkannya ke file yang sama.

5.4.3 Verifikasi Output dan Pengembangan Lanjutan

Beri izin eksekusi lalu jalankan script sesuai kebiasaan dari Bab 1.

chmod +x laporan_proses.sh
./laporan_proses.sh

Setelah mengetik angka, misalnya 5, dan menekan Enter, output di layar kurang lebih terlihat seperti berikut, dengan angka di kolom pertama menunjukkan jumlah proses milik user tersebut.

Tampilkan berapa banyak user teratas? 5
     42 www-data
     18 root
      6 mysql
      3 budi
      1 sshd

Periksa isi file laporan untuk memastikan tee benar-benar menuliskan hasil yang sama ke dalam file.

cat laporan_proses_user.txt

Script ini bisa dikembangkan lebih jauh, misalnya menambahkan redirection stderr terpisah untuk menangkap error jika ps gagal dijalankan karena keterbatasan izin akses, atau dijadwalkan berjalan otomatis lewat cron di Bab 18 dengan outputnya dikirim sebagai notifikasi lewat webhook seperti dibahas di Bab 20. Kombinasi read untuk input interaktif, redirection untuk logging, dan pipe untuk merangkai beberapa perintah kecil menjadi satu alur pemrosesan seperti pada studi kasus ini adalah pola yang akan terus muncul berulang kali di bab-bab berikutnya, termasuk saat mengolah teks dengan grep, sed, dan awk mulai Bab 9.