Menguasai pemrosesan paralel dan aliran data di Zsh: menjalankan perintah background dengan &, mengelola proses lewat jobs, bg, fg, wait, dan disown, membangun pipeline dengan |, memakai coprocess coproc untuk komunikasi dua arah, dan memanfaatkan multios untuk menulis ke banyak file sekaligus

Setelah di episode 13 tools produktivitas kalian lengkap, pada episode ini kita masuk ke pemrograman sistem: async, jobs, dan piping. Ketika kalian menjalankan backup besar, build, atau tail log, pertanyaan langsung muncul: "bagaimana menjalankan ini di background?" dan "bagaimana menggabungkan banyak perintah menjadi satu pipeline?"
Zsh menangani semua ini dengan baik — bahkan dengan fitur multios yang tidak dimiliki bash. Memahami job control dan pipeline bukan sekadar kenyamanan; ini fondasi untuk skrip deployment, cron job, dan otomasi yang akan kalian bangun di episode-episode berikutnya.
Menambahkan & di akhir perintah menjalankannya di background — prompt langsung kembali:
sleep 300 &
# [1] 28432 → nomor job [1], PID 28432Zsh melaporkan nomor job ([1]) dan process ID. Job background berjalan paralel; output tetap menuju terminal yang sama (bisa digabung dengan redirect untuk memisahkan).
./backup.sh > backup.log 2>&1 &Lihat semua job aktif dengan jobs:
jobs -l
# [1] + running sleep 300
# [2] - running ./backup.shKendalikan perintah yang berjalan di foreground:
# Jalankan foreground lalu tekan Ctrl-Z untuk suspend:
sleep 300
^Z
# [1] + suspended sleep 300
bg # lanjutkan di background
fg %1 # bawa kembali job 1 ke foregroundNotasi %n merujuk ke nomor job. Ctrl-Z (suspend) + bg adalah pola "ops, saya tidak mau menunggu".
wait memblokir sampai job (atau semua job) selesai. Penting dalam skrip yang menjalankan pekerjaan paralel lalu menggabungkan hasil:
./build_frontend.sh &
./build_backend.sh &
wait
print "Kedua build selesai"./build_a.sh & job_a=$!
./build_b.sh & job_b=$!
wait $job_a
print "build_a selesai"$! menampung PID dari job yang baru saja di-background — pola standar untuk melacak job tertentu.
disown melepaskan job dari kontrol shell sehingga ia tetap berjalan saat terminal ditutup (mirip nohup):
./long_task.sh &
disown
# sekarang job tidak lagi terdaftar di `jobs`Setelah disown, job bertahan walau sesi shell ditutup. Kombinasi umum: disown + redirect output ke file + log dengan timestamp.
Setiap perintah menghasilkan exit code; Zsh menyimpannya di $? dan $pipestatus untuk pipeline:
false
print $? # 1
true
print $? # 0
# pipeline — semua status dalam array
cmd1 | cmd2
print $pipestatus # status tiap elemen pipeline
print $pipestatus[1]$pipestatus adalah array (ingat: 1-indexed) berisi exit code setiap tahap pipeline — fitur yang tidak ada di bash (di sana hanya $? perintah terakhir).
Pipeline menghubungkan stdout satu perintah ke stdin perintah berikutnya:
ps aux | grep nginx | awk '{print $2}'
tail -f app.log | grep -i error
curl -s example.com | jq .namePipeline mentransmisikan stream — data mengalir bertahap, bukan menunggu selesai. Inilah kenapa tail -f | grep menampilkan baris secara real-time.
coprocess (coproc) menjalankan perintah dan membuka dua file descriptor untuk komunikasi dua arah: $COPROC (input) dan $COPROC_OUT (output).
coproc python3 -c 'while True: print(input())'
print "hello" >&p
read -p line
print $line # hello (dibalas python)Penjelasan:
coproc python3 ... — jalankan python sebagai coprocess.>&p — tulis ke coprocess (file descriptor p).read -p — baca dari coprocess.Coprocess berguna untuk interaksi berkelanjutan dengan program eksternal (misalnya REPL, client database). Di praktik modern, kebanyakan orang memilih pendekatan file/Named Pipe (FIFO) — tetapi coproc tetap tool yang sah di kotak peralatan Zsh.
Multios memungkinkan menulis ke banyak file sekaligus dalam satu perintah — fitur yang tidak dimiliki bash:
./deploy.sh > deploy.log > /var/log/deploy.txt
# output deploy.sh ditulis ke KEDUA file
# gabungkan juga dengan pipe:
./build.sh > build.log | tail -f
# log ke file DAN stream ke tailMultios bekerja karena Zsh mengubah > a > b menjadi "duplikat stream". Ini membuat trik seperti tee tanpa perintah tee:
# cara klasik
./script.sh 2>&1 | tee script.log
# cara multios
./script.sh > script.log >&1Penting: multios aktif di Zsh secara default; jika dibutuhkan untuk mematikan (agar > a > b hanya menimpa b), gunakan setopt no_multios.
Warning
Multios mengubah perilaku redirect bertingkat. Jika skrip bash yang menulis > a > b (yang di bash hanya menimpa b) dijalankan dengan Zsh, hasilnya berbeda: keduanya tertulis. Untuk skrip portabel, hindari redirect beruntun — pakai tee atau satu redirect saja.
Pola skrip untuk menjalankan tugas paralel dengan log terpisah dan menunggu semuanya:
#!/usr/bin/env zsh
set -euo pipefail
run_async() {
local name="$1" cmd="$2"
( eval "$cmd" > "${name}.log" 2>&1 ) &
}
run_async frontend "npm run build"
run_async backend "go build ./..."
run_async db "pg_dump prod > db.sql"
wait
print "Semua task selesai. Cek:"
ls -l *.logCatatan: subshell ( ... ) membuat setiap job punya scope terpisah, dan wait tanpa argumen menunggu semuanya — pola yang sering dipakai di pipeline CI.
& di dalam if — if cmd & then mengeksekusi if pada exit code cmd yang di-background, bukan hasilnya; selalu bungkus dalam subshell jika ragu.wait tanpa guard — di skrip dengan errexit, wait yang gagal bisa menghentikan seluruh skrip; tangani dengan wait || true bila diinginkan.coproc (dua arah) dengan | (satu arah); memakai | untuk komunikasi dua arah adalah kesalahan umum.tee.Inti yang harus dibawa pulang:
& untuk background, Ctrl-Z/bg/fg untuk beralih mode, jobs untuk daftar.wait $pid menunggu job; disown melepaskan agar bertahan setelah terminal ditutup.| menghubungkan stream; $pipestatus memberi status tiap tahap.coproc untuk komunikasi dua arah; multios > a > b menulis ke banyak file sekaligus — fitur unik Zsh.Di episode 15 selanjutnya kita akan membahas environment & PATH management — mengelola $PATH/$path dengan typeset -U untuk dedupe otomatis, guard [ -d ] sebelum menambah path, ekspor variabel environment, plus modul zsh/datetime dan zsh/mathfunc untuk skrip yang butuh waktu dan kalkulasi. Sampai jumpa di episode 15!