kill / signals
kill sends signals to processes — not just SIGTERM/SIGKILL but a whole vocabulary for graceful shutdown, config reload, debugging. kill, pkill, killall, pgrep, and jobs/fg/bg together cover most process management.
Signals, pkill, traps, find pids
EXAMPLE
# 1) Find process IDs
ps -ef | grep nginx # full output, filter
ps aux | grep -i postgres
pgrep -fl nginx # PIDs + cmdline; usually cleaner
pgrep -u mara node # by user
pidof nginx # main pid
fuser -k 8080/tcp # kill whatever holds tcp/8080
lsof -ti :3000 # PID listening on port 3000
ss -tlnp | grep :3000 # what's listening
# 2) Basic kill — default is SIGTERM (15)
kill 1234 # SIGTERM
kill -15 1234 # explicit
kill -TERM 1234 # by name
# 3) Common signals
# 1 SIGHUP — reload config (nginx, httpd, daemons)
# 2 SIGINT — Ctrl+C
# 3 SIGQUIT — Ctrl+\ → dump core
# 9 SIGKILL — uncatchable; immediate kill
# 15 SIGTERM — polite termination
# 18 SIGCONT — resume
# 19 SIGSTOP — pause (uncatchable)
# 20 SIGTSTP — Ctrl+Z
# USR1 / USR2 — app-defined; commonly 'reopen logs' / 'rotate'
kill -HUP 1234 # ask nginx to reload
kill -USR1 1234 # nginx: reopen log files
kill -USR2 1234 # nginx: live binary upgrade
# 4) SIGTERM vs SIGKILL
kill 1234 # asks nicely; app catches; cleans up
kill -9 1234 # KERNEL forces; no chance to clean up
# Prefer TERM. Only use KILL when:
# • App hung (not responding to TERM after 10-30s)
# • Shutdown signal not implemented
# • Last resort
# 5) Patterns by name
pkill -TERM nginx # send TERM to all matching cmdline
pkill -f 'node server.js' # match against FULL cmdline
pkill -u mara -TERM # by user
killall nginx # similar, but matches exact process name (no path)
# 6) Verify before killing
pgrep -fa nginx # show what WOULD be killed (-a shows cmdline)
pkill -n -f 'node old.js' # -n: kill NEWEST match only
# 7) Graceful shutdown handler — example app
# trap signals → drain → exit cleanly
# Node
function shutdown(signal) {
console.log(`${signal} received, draining`);
server.close(() => process.exit(0));
setTimeout(() => process.exit(1), 10_000).unref(); // force exit after 10s
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
# Python
import signal, sys
def handler(sig, frame):
print(f'{signal.Signals(sig).name} received')
sys.exit(0)
signal.signal(signal.SIGTERM, handler)
# Go
import "os/signal"; import "syscall"
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
<-c
// drain
# 8) Background + foreground jobs (interactive shell)
long-running-command & # run in background
jobs # list
fg %1 # bring job 1 to foreground
bg %1 # resume in background
Ctrl+Z # suspend foreground (SIGTSTP)
bg # resume in background
disown -h %1 # detach so it survives shell exit
nohup long-running & # immune to HUP signals
# 9) Killing process trees
kill -- -PGID # negative number = process GROUP
killpg PGID # equivalent
# Get PGID:
ps -o pgid= -p 1234
# Useful when a parent forks children; kill the GROUP not the PID.
# Systemd:
systemctl kill --signal=SIGTERM nginx.service
systemctl kill --kill-who=main nginx.service
# 10) Resource constraints + watchdog
# Process keeps respawning despite kill?
# • Check supervisor: systemd, supervisord, upstart
# • Stop the SERVICE, not the PID
systemctl stop nginx
supervisorctl stop myapp
# 11) Killing in scripts (graceful with timeout)
kill -TERM $PID
for i in {1..10}; do
if ! kill -0 $PID 2>/dev/null; then break; fi
sleep 1
done
kill -KILL $PID 2>/dev/null # nuke if still alive
# kill -0 checks existence without sending a real signal.
# 12) Common patterns by goal
# Graceful restart of nginx:
sudo systemctl reload nginx # SIGHUP
# Reload Postgres config:
sudo systemctl reload postgresql
# OR
sudo -u postgres pg_ctl reload
# Kill a hung SSH session:
ps -ef | grep ssh
kill -9 $PID
# Free a port:
fuser -k 3000/tcp
# Or:
lsof -ti :3000 | xargs -r kill
# 13) Common bugs
# • Sending SIGKILL by reflex → data loss / orphan files
# • kill -9 on a Docker container → container exits 137; orchestrator may restart
# • pkill -f matching too broadly → killed unintended processes
# • Trap handler in shell script + Ctrl+C → trap fires, but child still running
# • Killing PID 1 inside a container → container stops; intentional but surprising
# • Forgetting permissions — kill requires same UID OR root
# • Race: signal sent before app installed handler → exits immediately
# • Detached job + shell exit → SIGHUP kills it; use nohup or disown
# • TERM after KILL — KILL already killed; the process is gone or unreachable
Why it matters
Default to SIGTERM and let apps shut down cleanly; reserve SIGKILL for genuinely hung processes. Use pkill -f for pattern matches, kill -HUP to reload configs, kill -0 to test liveness, and wrap your apps with proper signal handlers so graceful shutdown actually happens during deploys.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…