Setiap kill %1 dan setiap Ctrl+C yang kita pakai sejauh ini sebenarnya mengirimkan hal yang sama: sinyal — pesan pendek bernomor dari kernel kepada sebuah proses, yang bisa berarti “berhenti”, “berhenti sementara”, atau “lanjutkan”. Nama perintah kill menyesatkan — tugas aslinya mengirim sinyal apa pun ke proses mana pun. Chapter ini membedah sinyal yang paling sering dipakai, konvensi exit status 128 + nomor sinyal, penangkapan sinyal dengan trap, serta alat penghenti massal pkill dan kerabatnya.

Sinyal: Pesan Asinkron dari Kernel #

Sinyal tidak masuk lewat antrean perintah program — ia menyela kapan saja di antara dua instruksi yang sedang dijalankan proses. Begitu tiba, proses menanggapi menurut disposition bawaannya: berhenti, berhenti sementara, diabaikan, atau ditangani handler miliknya. Sebagian besar sinyal bisa ditangkap dan diganti perilakunya; dua pengecualian mutlak adalah SIGKILL dan SIGSTOP — keduanya dikerjakan kernel tanpa pernah sampai ke proses. Tabel berikut merangkum yang paling sering kita jumpai:

NamaNomorPemicu umumPerilaku bawaan
SIGHUP1terminal terputus, logoutproses berhenti
SIGINT2Ctrl+Cproses berhenti
SIGQUIT3Ctrl+\proses berhenti + core dump
SIGKILL9kill -9berhenti seketika, tak bisa ditangkap
SIGTERM15kill tanpa opsiproses berhenti, bisa ditangkap
SIGCONT18bg, fgproses berhenti sementara dilanjutkan
SIGSTOP19Ctrl+Zberhenti sementara, tak bisa ditangkap

SIGINT adalah sinyal yang kita kirim setiap hari lewat Ctrl+C. Karena ini interaksi papan tombol di shell interaktif, berikut contoh tampilan sesinya, bukan output terverifikasi:

console
budi@laptop-budi:~$ sleep 600
^C
budi@laptop-budi:~$

Driver terminal mengubah Ctrl+C menjadi SIGINT untuk proses foreground, sleep mati tanpa kata pamit, dan prompt kembali. Nomor-nomor pada tabel di atas adalah versi arsitektur x86; daftar lengkap untuk mesin kita ada di halaman manual signal(7) .

kill: Mengirim Sinyal, Bukan Membunuh #

Tanpa argumen sinyal, kill memilih SIGTERM — permintaan berhenti yang santun karena masih bisa ditangkap program. Proses yang mati karena sinyal meninggalkan jejak pada exit status: shell melaporkannya sebagai 128 + nomor sinyal. Mari kita buktikan ketiganya sekaligus:

bash
sleep 5 & pid=$!
kill -INT $pid
wait $pid
echo "SIGINT  = exit $?"
sleep 5 & pid=$!
kill $pid
wait $pid
echo "SIGTERM = exit $?"
sleep 5 & pid=$!
kill -9 $pid
wait $pid
echo "SIGKILL = exit $?"

Output yang Dihasilkan:

text
SIGINT  = exit 130
SIGTERM = exit 143
SIGKILL = exit 137

Mari kita telaah blok di atas:

  1. Baris 1-4 (sleep 5 &, kill -INT, wait, echo): proses latar dihentikan dengan SIGINT (nomor 2), lalu wait mengambil statusnya: 130 = 128 + 2.
  2. Baris 5-8 (kill tanpa opsi): SIGTERM (15) menghasilkan 143 = 128 + 15 — angka yang sudah kita jumpai pada Chapter Foreground dan Background Processes .
  3. Baris 9-12 (kill -9): SIGKILL (9) menghasilkan 137 = 128 + 9. Job latar yang mati karena SIGKILL dilaporkan bash dengan baris Killed di layar — di stdout blok ini ia tidak muncul.

Nama atau Nomor dengan kill -l #

Tiga cara penulisan sinyal setara: kill -9 1234, kill -KILL 1234, dan kill -s KILL 1234. Penerjemahnya adalah builtin kill -l: dari nomor ke nama bila diberi angka, dan sebaliknya:

bash
for nomor in 1 2 9 15; do
  printf 'SIG%-7s = sinyal nomor %d\n' "$(kill -l $nomor)" "$nomor"
done
echo "---"
kill -l TERM
kill -l KILL

Output yang Dihasilkan:

text
SIGHUP     = sinyal nomor 1
SIGINT     = sinyal nomor 2
SIGKILL    = sinyal nomor 9
SIGTERM    = sinyal nomor 15
---
15
9

Mari kita telaah blok di atas:

  1. Baris 1-3 (for nomor in ...): untuk empat nomor sinyal, kill -l $nomor menerjemahkannya menjadi nama, lalu printf merapikan kolomnya — %-7s meratakan nama ke kiri selebar tujuh karakter.
  2. Baris 5-6 (kill -l TERM dan kill -l KILL): arah sebaliknya — nama menjadi nomor; berguna saat menemukan angka seperti -15 di dokumentasi dan ingin tahu sinyal apa yang dimaksud.

Tanpa argumen, kill -l mencetak seluruh daftar sinyal yang dikenal shell; sintaks lengkapnya ada di halaman manual kill(1) .

Menangkap Sinyal dengan trap #

Karena SIGTERM bisa ditangkap, program yang santun menggunakannya sebagai momen perapihan: menutup file, memutus koneksi database, lalu keluar. Di skrip bash, handler dipasang dengan trap 'aksi' NAMA-SINYAL. Skrip berikut menolak mati tanpa pamit:

bash
cat > penjaga.sh << 'EOF'
#!/bin/bash
trap 'echo "penjaga menerima sinyal TERM dan berhenti dengan rapi"; exit 0' TERM
while true; do sleep 1; done
EOF
chmod +x penjaga.sh
./penjaga.sh & pid=$!
sleep 0.5
kill -TERM $pid
wait $pid
echo "setelah SIGTERM: exit $?"
./penjaga.sh & pid=$!
sleep 0.5
kill -KILL $pid
wait $pid
echo "setelah SIGKILL: exit $?"

Output yang Dihasilkan:

text
penjaga menerima sinyal TERM dan berhenti dengan rapi
setelah SIGTERM: exit 0
setelah SIGKILL: exit 137

Mari kita telaah blok di atas:

  1. Baris 1-5 (heredoc penjaga.sh): skrip berisi loop sleep 1 tanpa henti; satu-satunya pintu keluarnya adalah trap yang mencetak pesan lalu exit 0 saat SIGTERM tiba — penundaan hingga satu detik itu wajar, karena bash menyelesaikan perintah yang sedang berjalan lebih dulu.
  2. Baris 6-11 (./penjaga.sh &, kill -TERM, wait): handler bekerja — pesan tercetak dan proses berhenti dengan status 0, bukan 143, karena kematiannya kini disengaja skrip sendiri.
  3. Baris 12-16 (kill -KILL lalu wait): SIGKILL tidak pernah sampai ke trap — skrip mati seketika dengan status 137 tanpa mencetak apa pun.

Menghentikan Berdasarkan Nama: pgrep dan pkill #

Menyalin PID dari ps satu per satu melelahkan untuk pekerjaan berulang. Pasangan pgrep dan pkill bekerja atas nama proses: pgrep mencarinya, pkill mengirim sinyal ke semua yang cocok sekaligus. Opsi -x meminta kecocokan persis pada nama proses — berikut dua worker kecil yang kita hentikan sekaligus:

bash
printf '#!/bin/bash\nsleep 5\n' > pdemo.sh
chmod +x pdemo.sh
./pdemo.sh & a=$!
./pdemo.sh & b=$!
sleep 0.3
echo "pgrep menemukan $(pgrep -xc pdemo.sh) proses pdemo.sh"
pkill -x pdemo.sh
wait $a; echo "pdemo.sh pertama berhenti dengan exit $?"
wait $b; echo "pdemo.sh kedua berhenti dengan exit $?"

Output yang Dihasilkan:

text
pgrep menemukan 2 proses pdemo.sh
pdemo.sh pertama berhenti dengan exit 143
pdemo.sh kedua berhenti dengan exit 143

Mari kita telaah blok di atas:

  1. Baris 1-4: skrip kecil pdemo.sh dijalankan dua kali di background — dua proses bernama sama, persis pola pekerjaan seperti worker pool.
  2. Baris 5-7 (sleep 0.3, pgrep -xc, pkill -x): setelah jeda agar kedua proses pasti hidup, pgrep -xc menghitung proses bernama persis pdemo.sh, lalu pkill -x mengirim SIGTERM ke keduanya sekaligus.
  3. Baris 8-9 (wait $a dan wait $b): kedua wait memanen status 143 masing-masing — bukti keduanya tumbang oleh sinyal yang sama.

Varian -f mencocokkan seluruh baris perintah, bukan hanya nama programnya — berguna untuk skrip berargumen panjang, tetapi berbahaya karena polanya bisa cocok dengan proses yang tak kita duga, termasuk shell yang sedang menjalankan perintah berisi kata itu. Kerabat dekatnya killall nama dari paket psmisc mengirim sinyal ke semua proses bernama persis nama; program itu tidak terpasang di lingkungan minimal buku ini tetapi tersedia di Debian dan Ubuntu, dan perilakunya terdokumentasi di halaman manual killall(1) serta pgrep(1) .

Kini kita bisa melahirkan proses di latar, menahannya, dan mengakhirinya dengan tingkat kesantunan yang kita pilih. Pertanyaan berikutnya soal keadilan: ketika ratusan proses berebut CPU, siapa yang berhak kebagian porsi lebih besar? Jawabannya ada pada nice value dan scheduler — materi Chapter Process Priority .