Setiap program Kotlin yang berjalan di terminal berinteraksi dengan tiga stream standar: standard input (stdin), standard output (stdout), dan standard error (stderr). Pemahaman tentang ketiga stream ini, ditambah kemampuan mengatur exit code dan menghasilkan output berwarna dengan ANSI escape, adalah fondasi bagi siapa pun yang membangun program CLI. Chapter ini membongkar konsep-konsep tersebut dan menunjukkan bagaimana program Kotlin berperilaku ketika outputnya di-pipe (|) atau di-redirect (>).

Tiga Stream Standar #

Sistem operasi Unix menyediakan tiga stream default untuk setiap program yang berjalan di terminal:

StreamNama file descriptorDi KotlinTujuan
stdinfd 0System.in``Membaca input pengguna
stdoutfd 1System.outOutput normal program
stderrfd 2System.errPesan error dan diagnostik

Pemisahan stdout dan stderr memungkinkan kita menjalankan program > output.txt dan tetap melihat pesan error di terminal — stderr tidak ikut di-redirect. Inilah dasar dari filosofi Unix: program yang baik mengirim data ke stdout dan diagnostik ke stderr.

Exit Code dengan exitProcess #

Setiap program CLI mengembalikan exit code (kode keluar) ke shell. Nilai 0 berarti sukses, nilai non-zero berarti ada kesalahan. Di Kotlin, kita dapat mengatur exit code dengan exitProcess(code):

kotlin
import kotlin.system.exitProcess

fun main(args: Array<String>) {
    val mode = args.getOrElse(0) { "stdout" }

    when (mode) {
        "stdout" -> {
            println("Pesan ke stdout")
            System.err.println("Pesan ke stderr")
        }
        "color" -> {
            val merah = "\u001B[31m"
            val hijau = "\u001B[32m"
            val kuning = "\u001B[33m"
            val reset = "\u001B[0m"
            println("${hijau}SUKSES${reset}: operasi berhasil")
            println("${kuning}PERINGATAN${reset}: ada catatan kecil")
            println("${merah}GAGAL${reset}: operasi tidak dapat dilanjutkan")
        }
        "exit" -> {
            val kode = args.getOrElse(1) { "0" }.toInt()
            println("Keluar dengan kode $kode")
            exitProcess(kode)
        }
        "echo" -> {
            var jumlah = 0
            while (true) {
                val baris = readlnOrNull() ?: break
                println("[$jumlah] $baris")
                jumlah++
            }
            println("Total baris: $jumlah")
        }
        else -> {
            println("Penggunaan: program [stdout|color|exit|echo]")
            exitProcess(2)
        }
    }
}

Output yang Dihasilkan:

text
Pesan ke stdout

Mari kita telaah baris-baris kode di atas:

  1. Baris 1 (import kotlin.system.exitProcess): function exitProcess berada di package kotlin.system. Function ini memanggil Runtime.getRuntime().exit(code) di balik layar dan segera menghentikan JVM.
  2. Baris 5 (args.getOrElse(0) { "stdout" }): argumen pertama menjadi mode operasi program. Jika tidak diberikan, defaultnya "stdout". Pola ini umum di CLI: satu argumen pertama sebagai sub-command.
  3. Baris 9 (println("Pesan ke stdout")): menulis ke stdout melalui System.out. Pesan ini akan ikut ter-redirect jika output di-pipe.
  4. Baris 10 (System.err.println(...)): menulis ke stderr melalui System.err. Pesan ini tidak ikut ter-redirect oleh > biasa — hanya redirect khusus 2> yang menangkapnya.
  5. Baris 12–19 (mode == "color"): menggunakan ANSI escape sequence untuk mewarnai output. Sequence \u001B[31m mengaktifkan warna merah, \u001B[32m hijau, \u001B[33m kuning, dan \u001B[0m mereset ke default.
  6. Baris 22 (exitProcess(kode)): menghentikan program dengan exit code yang diberikan. Setelah pemanggilan ini, kode di bawahnya tidak akan dieksekusi.
  7. Baris 27 (readlnOrNull() ?: break): pola loop membaca stdin hingga EOF. break keluar dari loop saat EOF. Inilah pola filter Unix yang membaca input baris-per-baris.
  8. Baris 35 (exitProcess(2)): konvensi exit code 2 untuk kesalahan penggunaan (usage error). Berbeda dengan exit code 1 yang biasanya berarti error runtime, kode 2 khusus untuk “argumen tidak valid”.

Exit Code dan Konvensi Unix #

KodeArti konvensional
0Sukses
1Error umum (kegagalan operasi)
2Kesalahan penggunaan (argumen invalid)
126File tidak dapat dieksekusi
127Command tidak ditemukan
130Dihentikan oleh Ctrl+C (SIGINT)

Shell menangkap exit code di variabel $? setelah program berakhir. Pola program && next menjalankan next hanya jika exit code 0; program || next sebaliknya.

Output Berwarna dengan ANSI Escape #

Terminal modern mendukung ANSI escape sequence untuk mengubah warna teks, latar, dan gaya (tebal, garis bawah). Formatnya selalu diawali \u001B[ dan diakhiri m:

kotlin Contoh: ANSI escape dasar
val merah = "\u001B[31m"
val hijau = "\u001B[32m"
val kuning = "\u001B[33m"
val biru = "\u001B[34m"
val tebal = "\u001B[1m"
val reset = "\u001B[0m"

println("${hijau}SUKSES${reset}: operasi berhasil")
println("${merah}${tebal}GAGAL${reset}: operasi tidak dapat dilanjutkan")

Beberapa kode warna umum:

KodeWarna
30 / 90Hitam / Abu terang
31 / 91Merah / Merah terang
32 / 92Hijau / Hijau terang
33 / 93Kuning / Kuning terang
34 / 94Biru / Biru terang
0Reset semua atribut
1Tebal (bold)
4Garis bawah (underline)

Untuk warna latar, ganti digit pertama 3 menjadi 4 (misalnya \u001B[41m untuk latar merah).

Pipe dan Redirect #

Shell Unix memungkinkan kita merangkai program dengan pipe | dan redirect >:

bash Contoh: pipe dan redirect
# Redirect stdout ke file (stderr tetap ke terminal)
java -jar app.jar stdout > out.txt

# Redirect stdout dan stderr ke file berbeda
java -jar app.jar stdout > out.txt 2> err.txt

# Redirect keduanya ke file yang sama
java -jar app.jar stdout > all.txt 2>&1

# Pipe output program A ke input program B
java -jar app.jar echo | grep "satu"

Saat program di-pipe, System.out tidak lagi terhubung ke terminal melainkan ke pipe. Method System.console() mengembalikan null ketika stdout adalah pipe — trik ini sering dipakai untuk mendeteksi apakah output akan ditampilkan ke pengguna atau diproses lebih lanjut.

Pola Unix Filter #

Program echo mode di app.kt menggambarkan pola Unix filter: baca stdin baris-per-baris, proses, tulis ke stdout. Pola ini dapat dirangkai dengan program lain:

bash Contoh: rangkaian pipe filter
printf "apel\njeruk\nmangga\n" | java -jar app.jar echo | grep "jeruk"
# Output: [1] jeruk

Filter kecil yang melakukan satu tugas dengan baik adalah dasar filosofi Unix. Banyak tool CLI klasik (grep, sed, awk, sort, uniq) mengikuti pola ini.

Referensi Lanjutan #

Dengan pemahaman tentang stream, exit code, ANSI color, dan perilaku pipe, kita menutup section Input/Output dan Formatting. Pada section berikutnya, kita akan menyelami topik yang lebih dalam tentang struktur kontrol Kotlin: control flow dengan if, when, dan loop.