Kendali job

Kendali job dengan &, fg, bg, dan jobs beserta perilaku nohup ketika sesi terminal ditutup.

Daftar isi

Setiap perintah yang dijalankan dari terminal menjadi proses yang diluncurkan dan diawasi oleh shell. Bash mengelompokkan proses tersebut sebagai job, yaitu satu unit eksekusi beserta seluruh proses turunannya yang dikelola bersama. Job dapat berjalan di foreground, sehingga terminal menunggunya selesai, maupun di background, sehingga terminal langsung siap menerima perintah berikutnya. Topik ini membahas cara memindahkan job antara keduanya dengan &, jobs, fg, bg, dan wait, dilanjutkan cara menjaga proses tetap hidup dengan nohup ketika sesi terminal ditutup.

Konsep job, foreground, dan background#

Ketika sebuah perintah diketik, shell membuat proses baru dan mengangkatnya menjadi job foreground. Hanya satu job foreground yang ada pada satu waktu, dan terminal mengarahkan masukan papan ketik ke job tersebut. Job background tetap berjalan setelah perintah diberikan, tetapi tidak lagi menerima masukan papan ketik, meskipun keluarannya tetap dicampur ke layar terminal. Mekanisme pengaturan ini disebut job control, yakni kemampuan shell mengawasi dan memindahkan status job.

Shell mencatat seluruh job miliknya dalam satu tabel job, sehingga statusnya dapat ditanyakan kapan pun. Job control penuh hanya aktif pada sesi interaktif, yaitu sesi tempat perintah diketik satu per satu. Pada sesi non-interaktif, misalnya ketika bash menjalankan isi skrip, job control dimatikan dan sebagian perintahnya menolak bekerja. Perbedaan ini akan terlihat pada bagian yang membahas fg dan bg. Dengan pemahaman tersebut, perintah-perintah pada bagian berikutnya dapat dibaca sebagai alat untuk memindahkan job antara dua posisi tersebut.

Menjalankan perintah di background dengan &#

Tanda & di akhir baris perintah menyuruh shell meluncurkan perintah sebagai job background. Shell tidak menunggu perintah itu selesai, sehingga sesi langsung dapat menerima perintah berikutnya. Nomor PID dari job terakhir disimpan dalam parameter khusus $!, sehingga prosesnya tetap dapat dirujuk nanti.

Blok berikut menjalankan sleep 30 di background, lalu mendaftarkannya dengan jobs. Dua perintah terakhir mematikan job tersebut agar sesi tetap bersih.

bash
sleep 30 &
jobs
kill %1
wait
text Keluaran
[1]+  Running                 sleep 30 &

Baris keluaran memuat banyak informasi padat. Angka 1 dalam tanda kurung siku adalah nomor job, penanda + menunjuk job terbaru, dan Running menyatakan statusnya. Teks sleep 30 & di akhir baris adalah perintah yang meluncurkan job tersebut. Perintah kill %1 mengirim sinyal, yaitu pesan singkat yang memicu reaksi tertentu pada proses penerima, ke job bernomor 1, sedangkan wait menunggu seluruh job berakhir sehingga tabel job kembali kosong.

Memantau job dengan jobs#

Perintah jobs mencetak isi tabel job milik sesi saat ini tanpa mengubah apa pun. Pemanggilan dapat dilakukan kapan saja, dan status tiap job diperbarui oleh shell setiap kali tabel itu diperiksa. Dua job dapat dijalankan sekaligus, dan jobs akan mendaftarkannya secara berurutan sesuai nomornya.

bash
sleep 30 &
sleep 25 &
jobs
kill %1 %2
wait
text Keluaran
[1]-  Running                 sleep 30 &
[2]+  Running                 sleep 25 &

Perhatikan penanda di belakang nomor job. Tanda + menunjuk job yang paling baru diluncurkan, sedangkan tanda - menunjuk job sebelumnya. Penanda ini penting ketika job dirujuk tanpa nomor, karena % tanpa angka merujuk pada job bertanda +. Dua job pada blok tersebut dimatikan sekaligus dengan kill %1 %2, lalu wait mengumpulkan keduanya.

Mengembalikan job dengan fg dan bg#

Pada sesi interaktif, perintah fg membawa job background kembali menjadi foreground, sehingga shell menunggunya lagi dan terminal mengarahkan papan ketik ke job tersebut. Sebaliknya, bg melanjutkan job yang sedang berhenti agar berjalan kembali di background. Keduanya dirujuk dengan nomor job, misalnya fg %1. Mekanisme ini merupakan bagian dari job control yang hanya tersedia pada sesi interaktif.

Pada sesi non-interaktif, seperti ketika bash menjalankan skrip, job control tidak diaktifkan dan kedua perintah langsung gagal. Blok berikut memperlihatkan kegagalan tersebut. Pesan errornya mengandung keterangan no job control, tetapi pesan itu ditekan dengan redirection 2>/dev/null agar keluaran blok tetap stabil, dan kode keluar 1 menjadi bukti kegagalannya.

bash
sleep 30 &
fg 2>/dev/null
echo "kode keluar fg: $?"
bg 2>/dev/null
echo "kode keluar bg: $?"
kill %1
wait
text Keluaran
kode keluar fg: 1
kode keluar bg: 1

Kode keluar 1 pada kedua baris menegaskan bahwa tanpa job control, pemindahan posisi job tidak dapat dilakukan. Di terminal interaktif yang dipakai sehari-hari, perintah yang sama berjalan normal. Perbedaan ini murni berasal dari jenis sesinya, bukan dari perintahnya.

Perintah wait menahan shell sampai job yang dirujuk berakhir. Tanpa argumen, ia menunggu seluruh job milik sesi, sedangkan wait %1 atau wait $! menunggu satu job tertentu. Kode keluar dari wait adalah kode keluar dari job yang ditunggu, sehingga perintah ini sekaligus menjadi jembatan untuk membaca hasil akhir sebuah job background.

bash
sleep 2 &
wait $!
echo "wait selesai dengan kode keluar $?"
text Keluaran
wait selesai dengan kode keluar 0

sleep 2 berhenti dengan sukses setelah dua detik, sehingga wait kembali dengan kode keluar 0. Apabila job dituntaskan oleh sinyal, wait melaporkan kode keluar 128 ditambah nomor sinyalnya, misalnya 143 untuk SIGTERM. Menggunakan wait juga lebih hemat daripada memeriksa status job berulang-ulang, karena shell benar-benar menunggu sampai jobnya selesai.

nohup dan sesi yang ditutup#

Apabila sesi terminal ditutup, shell mengirim sinyal SIGHUP, yaitu sinyal pemutus koneksi terminal yang bernomor 1, ke seluruh job miliknya. Job yang tidak menangani sinyal ini akan mati bersama sesinya. Perilaku ini menjelaskan mengapa proses background yang dibiarkan begitu saja sering sudah berhenti ketika sesi dibuka kembali.

Perintah nohup meluncurkan program dengan mengabaikan sinyal SIGHUP, sehingga program tetap hidup setelah terminalnya ditutup. Apabila keluarannya tidak dialihkan, nohup menuliskannya ke berkas nohup.out di direktori saat itu. Blok berikut menjalankan sleep 5 di bawah nohup dengan keluaran yang dialihkan ke berkas catatan.

bash
nohup sleep 5 > catatan.log 2>&1 &
sleep 0.2
jobs
ls catatan.log
text Keluaran
[1]+  Running                 nohup sleep 5 > catatan.log 2>&1 &
catatan.log

Baris keluaran dari jobs menampilkan perintah lengkap beserta redirection-nya, sehingga bentuk penyimpanan hasilnya langsung terbaca. Berkas catatan.log memang tercipta karena keluaran standar telah dialihkan ke sana secara eksplisit. Proses sleep 5 ini berhenti dengan sendirinya lima detik kemudian, tanpa perlu dimatikan.

Kesalahan umum#

Kekeliruan pada pengelolaan job jarang merusak program, tetapi sering membuat proses hilang tanpa jejak. Daftar berikut memuat yang paling sering ditemui beserta perbaikannya.

  • Meluncurkan proses jangka panjang dengan & tanpa nohup. Proses tersebut tetap terikat pada sesinya, sehingga SIGHUP yang dikirim ketika terminal ditutup mematikannya tanpa peringatan. Luncurkan ulang dengan nohup bila prosesnya harus bertahan.
  • Mengira job background tidak mencetak apa pun ke terminal. Keluaran dan pesan error job background tetap dicampur ke layar sehingga merusak keterbacaan sesi. Alihkan keduanya dengan redirection seperti > catatan.log 2>&1.
  • Merujuk %1 dari sesi shell yang berbeda. Tabel job adalah milik shell yang meluncurkan job tersebut, sehingga nomor % tidak berarti apa pun di shell lain. Gunakan PID dari $! untuk rujukan lintas sesi.
  • Membaca jobs sebagai daftar seluruh proses milik pengguna. jobs hanya menampilkan job milik sesi saat ini, sedangkan proses lain diperiksa dengan ps atau pgrep.

Ringkasan#

  • Tanda & meluncurkan perintah sebagai job background, dan $! menyimpan PID job terakhir.
  • jobs mendaftar job milik sesi dengan nomor, penanda + dan -, serta statusnya.
  • fg dan bg memindahkan posisi job, tetapi hanya bekerja pada sesi interaktif yang menjalankan job control.
  • wait menunggu job selesai dan mewariskan kode keluarnya, sedangkan nohup menjaga program tetap hidup dengan mengabaikan SIGHUP ketika sesi ditutup.

Referensi#