Operator & dan Ctrl+Z dari Chapter sebelumnya sama-sama melahirkan satu entri di tempat yang belum kita kunjungi: tabel job milik shell. Setiap pipeline yang dijalankan — baik di foreground maupun background — dicatat shell sebagai satu job bernomor, dan sekumpulan perintah disediakan untuk mengelolanya. Chapter ini membahas daftar itu dari ujung ke ujung: jobs untuk melihatnya, fg dan bg untuk memindahkan job antara dua keadaan, jobspec %1 untuk menunjuknya, dan disown untuk melepasnya dari sesi.

Job: Satu Pipeline dalam Tabel Shell #

Bagi shell, satu job adalah satu pipeline — baris perintah lengkap dengan semua pipanya. Perintah tar -czf arsip.tar.gz proyek/ | gzip & melahirkan dua proses (tar dan gzip), tetapi keduanya dicatat sebagai satu job [1]. Nomor job diberikan berurutan mulai dari 1, dan hanya berarti di dalam sesi shell yang melahirkannya; sesi lain punya tabelnya sendiri. Penanda + menunjuk job current — target bawaan bagi fg dan bg tanpa argumen — sedangkan - menunjuk job sebelumnya.

Melihat Daftar Job dengan jobs #

Perintah jobs mencetak isi tabel job sesi saat ini, lengkap dengan nomor, penanda, keadaan (Running, Stopped, atau Done), dan baris perintahnya. Opsi -l menambahkan PID di tiap baris. Karena tabel job hidup di shell interaktif, berikut contoh tampilan sesinya, bukan output terverifikasi:

console
budi@laptop-budi:~$ sleep 600 &
[1] 19001
budi@laptop-budi:~$ bash konversi-video.sh &
[2] 19002
budi@laptop-budi:~$ jobs -l
[1]-  19001 Running                 sleep 600 &
[2]+  19002 Running                 bash konversi-video.sh &

Dua pekerjaan latar sedang berjalan: sleep 600 sebagai job [1] dan konversi-video.sh sebagai job [2] yang menjadi job current (+). Ketika sebuah job berakhir, ia sempat tampil sebagai Done pada pemanggilan jobs berikutnya, lalu hilang dari tabel — daftar ini benar-benar hidup, bukan arsip.

Alur Kerja Klasik: Ctrl+Z lalu bg #

Rangkaian tombol paling sering dipakai dalam job control adalah memindahkan pekerjaan foreground ke background tanpa memulainya dari awal. Karena seluruh rangkaiannya adalah interaksi keyboard, berikut contoh tampilan sesinya, bukan output terverifikasi:

console
budi@laptop-budi:~$ tar -czf arsip.tar.gz proyek/
^Z
[1]+  Stopped                 tar -czf arsip.tar.gz proyek/
budi@laptop-budi:~$ bg
[1]+ tar -czf arsip.tar.gz proyek/ &
budi@laptop-budi:~$ fg %1
tar -czf arsip.tar.gz proyek/
^C

Alurnya empat langkah: Ctrl+Z membekukan tar lewat sinyal SIGTSTP sehingga prompt kembali; bg melanjutkannya di background lewat sinyal SIGCONT; fg %1 memanggilnya kembali ke foreground beserta terminalnya; Ctrl+C mengakhirinya lewat sinyal SIGINT. Tiga perintah terakhir menerima argumen opsional berupa jobspec — %1 untuk job nomor 1, %tar untuk job yang perintahnya diawali tar — dan tanpa argumen mereka menunjuk job bertanda +. Menghentikan job juga tidak perlu memanggilnya kembali: kill %1 mengirim sinyal langsung ke job, dan karena satu job adalah satu pipeline, seluruh proses di dalamnya menerima sinyal itu sekaligus.

Mensimulasikan Job Control dalam Skrip #

Perintah fg dan bg butuh terminal interaktif — keduanya mengatur siapa yang berhak membaca keyboard — sehingga keduanya tidak berarti di skrip. Tetapi tabel job sendiri bisa dihidupkan di shell non-interaktif dengan set -m (monitor mode), dan itulah cara kita menguji jobs serta jobspec secara deterministik: setiap sesi di bungkus dalam bash -c anak.

bash
bash -c 'set -m
sleep 40 &
sleep 30 &
jobs
kill %1 %2
wait
echo "kedua job dihentikan lewat jobspec"'

Output yang Dihasilkan:

text
[1]-  Running                 sleep 40 &
[2]+  Running                 sleep 30 &
kedua job dihentikan lewat jobspec

Mari kita telaah blok di atas:

  1. Baris 1 (bash -c 'set -m ...): seluruh sesi berjalan di shell anak, dan set -m menghidupkan tabel job di dalamnya — meniru perilaku shell interaktif.
  2. Baris 2-3 (sleep 40 & dan sleep 30 &): dua job latar dilahirkan; job kedua menjadi job current sehingga bertanda +.
  3. Baris 4 (jobs): mencetak kedua job beserta keadaan Running dan baris perintahnya.
  4. Baris 5-7 (kill %1 %2, wait, echo): kedua job dihentikan lewat jobspec tanpa menyentuh PID, wait memanen sisa-sisanya, lalu pesan penutup membuktikan keduanya pergi.

wait juga menerima jobspec, jadi skrip bisa menunggu job tertentu tanpa pernah tahu PID-nya:

bash
bash -c 'set -m
sleep 1 &
wait %1
echo "job 1 selesai dengan exit status $?"'

Output yang Dihasilkan:

text
job 1 selesai dengan exit status 0

Blok pendek ini melengkapi blok sebelumnya: %1 dan $! adalah dua pegangan untuk objek yang sama — nomor job dari sisi shell, PID dari sisi kernel — dan keduanya sah dipakai di wait maupun kill.

disown: Melepas Job dari Tabel Shell #

Saat sesi terminal berakhir, shell yang menerima SIGHUP meneruskan sinyal itu kepada semua job di tabelnya — itulah mengapa pekerjaan latar ikut mati saat kita logout. Perintah disown mengeluarkan job dari tabel tanpa menghentikan prosesnya, sehingga pekerjaan itu luput dari penerusan sinyal tersebut:

bash
bash -c 'set -m
sleep 30 &
jobs
echo "--- setelah disown ---"
disown
jobs
echo "(daftar job kosong)"
kill $!
wait 2>/dev/null
echo "prosesnya tetap harus dihentikan manual"'

Output yang Dihasilkan:

text
[1]+  Running                 sleep 30 &
--- setelah disown ---
(daftar job kosong)
prosesnya tetap harus dihentikan manual

Mari kita telaah blok di atas:

  1. Baris 1-3 (bash -c 'set -m ... jobs): satu job latar dilahirkan di shell anak dan tercatat di tabelnya.
  2. Baris 4-7 (disown dan jobs): disown tanpa argumen melepas semua job; pemanggilan jobs kedua tidak lagi mencetak apa pun karena tabelnya kosong.
  3. Baris 8-10 (kill $!, wait, echo): prosesnya sendiri tetap hidup — $! masih menyimpan PID-nya — sehingga penghentiannya tetap tugas kita, bukan tugas shell.

disown juga menerima jobspec (disown %1) bila hanya sebagian job yang ingin dilepas. Bedanya dengan nohup ada pada waktunya: nohup memasang kebalikan SIGHUP sejak proses lahir, sedangkan disown melepas job yang sudah berjalan setelah kita sadar pekerjaan itu akan lama. Keduanya sering dipakai berurutan di sesi SSH: disown menyelamatkan job dari logout, dan tuntasnya dibaca di wiki ProcessManagement serta bagian JOB CONTROL halaman manual bash(1) .

Dari awal chapter ini kita memakai satu kata kerja berulang tanpa membongkarnya: mengirim sinyal. SIGTSTP membekukan job, SIGCONT melanjutkannya, dan kill %1 mengakhirinya — semuanya adalah pesan-pesan asinkron dari kernel kepada proses. Bab berikutnya membedah pesan itu sendiri: sinyal, konvensinya, dan perbedaan besar antara permintaan santun SIGTERM dan vonis mutlak SIGKILL di Chapter Signals dan Process Termination .