Skip to content
TaeyoungKim.dev

Linux kill vs kill -9: Confirm the process and allow cleanup

LinuxWritten 3 min readTaeyoungKim
LinkedInX

When a program will not exit, kill -9 can seem like the quickest fix. It can also deny the program a chance to close files or finish its own shutdown work. First confirm which process will receive the signal and whether it actually exits afterward.

How do kill and kill -9 differ?

kill PID normally sends SIGTERM, a request to terminate. A program with a TERM handler can run cleanup and then exit; without one, the signal's default action is termination. Sending TERM does not create cleanup code automatically.

kill -9 PID sends SIGKILL. A process cannot catch or ignore this signal, so it cannot run its own signal-handler cleanup. The Linux signal(7) manual documents these signal behaviors.

The TERM path in the diagram assumes a program that implements shutdown handling. The KILL path does not allow its own signal handler to run.

How can you observe the result using your own process?

This Bash example starts its own short-lived worker and signals only that worker's PID. A worker.ready file indicates that the worker started; it does not use the PID of another running service.

bash
lab_dir=$(mktemp -d) || exit 1

worker() {
  label=$1
  trap 'printf "cleanup\n" >> "$lab_dir/$label.log"; exit 0' TERM
  : > "$lab_dir/$label.ready"
  while :; do sleep 0.1; done
}

run_case() {
  label=$1
  signal=$2
  worker "$label" &
  worker_pid=$!

  for attempt in 1 2 3 4 5 6 7 8 9 10; do
    [ -e "$lab_dir/$label.ready" ] && break
    sleep 0.05
  done
  [ -e "$lab_dir/$label.ready" ] || return 3

  ps -p "$worker_pid" -o pid=,stat=,comm=
  kill -"$signal" "$worker_pid"
  wait "$worker_pid" 2>/dev/null
  status=$?

  if [ -s "$lab_dir/$label.log" ]; then
    printf '%s: status=%s, cleanup=yes\n' "$label" "$status"
  else
    printf '%s: status=%s, cleanup=no\n' "$label" "$status"
  fi
}

run_case term TERM
run_case kill KILL

One Bash run produced this output. PIDs vary every time:

text
4809 S    bash
term: status=0, cleanup=yes
4813 S    bash
kill: status=137, cleanup=no

$! is the PID of the just-started background job. In ps, S means it is sleeping, not necessarily broken. The TERM handler wrote a cleanup record and exited with 0; the KILL case wrote none. Here 137 is Bash's observed exit status for a process killed by signal 9. Do not treat that number alone as a universal diagnosis for unrelated programs.

Why check again after kill succeeds?

A successful kill command means the signal request was accepted, not that shutdown and cleanup are complete. wait in the example waits for a child started by the current shell; it cannot wait this way for a process launched by another shell or service.

For an operational process, verify its PID, command, and user before sending a signal. Check its service manager and logs for the final state. A PID noted earlier might already have been reused by another process.

If a process remains after TERM, inspect whether it handles the signal, whether cleanup is in progress, and whether a service manager restarted it. Consider a forced stop and its recovery impact only after an agreed shutdown window has passed.

Key takeaways

kill requests termination with TERM; kill -9 forces it without an opportunity for the process's own signal-handler cleanup. Confirm the target and observe actual shutdown before escalating to KILL.

Author

TaeyoungKim

Connecting technical foundations with implementation, verification, and production decisions.

#Linux#kill#kill -9#SIGTERM#SIGKILL

Read next