Piping & Redirection — Terminal

Piping & Redirection Piping dan redirection adalah fitur yang membuat terminal sangat powerful. Mereka memungkinkan kamu menghubungkan perintah-perintah kecil…

Perintah terminal itu kecil-kecil: grep cuma menyaring baris, wc cuma menghitung, sort cuma mengurutkan. Pipe (|) menyambungkan mereka jadi satu rangkaian, dan redirection (>, >>, 2>) mengarahkan hasilnya ke file, bukan ke layar. Mirip ban berjalan di pabrik: tiap pekerja mengambil barang dari ban, mengerjakan satu tugas, lalu menaruhnya lagi untuk pekerja berikutnya. Di ujung ban, barangnya dipajang di etalase (layar), atau masuk kardus (file) kalau kamu minta.

🧪 Tebakan cepat: kamu menjalankan echo "deploy" > catatan.txt dua kali. Isi catatan.txt jadi satu baris atau dua baris? Tebak dulu, jawabannya ada di bagian "Redirect: simpan hasil ke file".

Tiga saluran: stdin, stdout, stderr

Setiap program yang jalan punya tiga saluran data, masing-masing dengan nomor:

Nomor Nama Isinya Defaultnya
0 stdin (standard input) data yang masuk ke program keyboard
1 stdout (standard output) hasil normal layar
2 stderr (standard error) pesan error layar

stdout dan stderr sama-sama muncul di layar, jadi kelihatannya satu. Padahal itu dua saluran terpisah, dan bedanya baru terasa waktu kamu memakai pipe dan redirect.

Pipe: output kiri jadi input kanan

Contohnya app.log, log sebuah server yang isinya 6 baris:

INFO: Server started
ERROR: Database timeout
INFO: Request handled
ERROR: File not found
ERROR: Permission denied
INFO: Cache cleared

Ada berapa baris ERROR?

$ cat app.log | grep ERROR | wc -l
3
Tahap Perintah Yang dia keluarkan
1 cat app.log 6 baris isi file
2 grep ERROR 3 baris yang mengandung ERROR
3 wc -l 3, jumlah baris yang dia terima

Urutannya penting. cat app.log | wc -l | grep ERROR gak mencetak apa-apa: wc -l sudah mengubah 6 baris jadi angka 6, dan angka itu gak mengandung ERROR.

Satu lagi: wc -c menghitung byte, dan echo selalu menambahkan karakter baris baru di akhir. Jadi echo "hello" | wc -c hasilnya 6: 5 huruf ditambah 1 baris baru.

Redirect: simpan hasil ke file

$ echo "deploy pertama" > catatan.txt
$ echo "deploy kedua" >> catatan.txt
$ cat catatan.txt
deploy pertama
deploy kedua
$ echo "deploy ketiga" > catatan.txt
$ cat catatan.txt
deploy ketiga

Jadi echo "deploy" > catatan.txt dua kali tetap menghasilkan satu baris: tulisan kedua menimpa yang pertama. Mau dua baris, pakai >>. Itu jawaban tebakannya.

Pipe dan redirect bisa digabung. Redirect stdout ditulis di ujung perintah terakhir:

cat app.log | grep ERROR > hasil.txt          # 3 baris ERROR masuk hasil.txt, layar kosong
cat app.log | grep ERROR | wc -l >> hasil.txt  # angka 3 ditambahkan di akhir hasil.txt

Kebalikannya ada <: isi file dikirim ke stdin. wc -l < app.log mencetak 6 saja, sedangkan wc -l app.log mencetak 6 app.log, karena kali ini wc tahu nama file-nya.

Error punya jalurnya sendiri

Kalau cat diminta membaca file yang gak ada, pesan error-nya keluar lewat stderr:

$ cat app.log lama.log | grep ERROR | wc -l
cat: lama.log: No such file or directory
3

Pipe cuma mengalirkan stdout. Pesan error dari cat gak masuk ke grep, dia langsung muncul di layar, dan hasilnya tetap 3. Untuk memindahkan stderr, tulis nomornya di depan >:

cat app.log lama.log 2> error.txt | grep ERROR | wc -l  # layar cuma 3, error masuk error.txt
find / -name "*.conf" 2> /dev/null                      # buang semua pesan error
npm run build > build.log 2>&1                          # stdout dan stderr ke file yang sama

Pipe di JavaScript: fungsi pipe

Ide yang sama bisa ditulis di JavaScript, dan itulah latihan pelajaran ini. pipe(f, g) mengembalikan function baru: input masuk ke f, lalu hasil f masuk ke g.

function pipe(...fns) {
  return (input) => fns.reduce((value, fn) => fn(value), input);
}

const logLines = [
  "INFO: Server started",
  "ERROR: Database timeout",
  "INFO: Request handled",
  "ERROR: File not found",
  "ERROR: Permission denied",
  "INFO: Cache cleared"
];

const filterErrors = (lines) => lines.filter((l) => l.includes("ERROR")); // seperti grep ERROR
const countLines = (lines) => lines.length; // seperti wc -l

const countErrors = pipe(filterErrors, countLines);
console.log(countErrors(logLines)); // 3

pipe((n) => n + 1, (n) => n * 2)(3) hasilnya 8: 3 masuk ke function pertama jadi 4, lalu 4 masuk ke function kedua jadi 8. Urutannya dari kiri ke kanan, sama seperti | di terminal. Dan pipe()(5) tanpa function sama sekali mengembalikan 5: reduce gak punya apa pun untuk dijalankan, jadi yang keluar nilai awalnya.

⚠️ Jebakan yang sering ketemu

TL;DR: Tiap program punya stdin (0), stdout (1) dan stderr (2). | menyambungkan stdout kiri ke stdin kanan: cat app.log | grep ERROR | wc -l mencetak 3. > menulis stdout ke file dan menimpa isinya, >> menambah di akhir, < membaca file sebagai stdin. Error lewat stderr, gak ikut pipe atau >; pindahkan dengan 2> file, buang dengan 2> /dev/null, gabungkan dengan > file 2>&1. echo "hello" | wc -c hasilnya 6 karena ada baris baru. Di JavaScript, pipe(...fns) mengembalikan (input) => fns.reduce((value, fn) => fn(value), input), dari kiri ke kanan.

Yang akan kamu pelajari