Signals
A signal is a limited, asynchronous message sent to a process - the mechanism behind Ctrl+C, graceful service shutdowns, and forcibly killing something that won't respond.
A signal interrupts a process to notify it of an event, with no payload beyond the signal number itself. A process can choose to handle most signals with custom logic, ignore them, or take the kernel's default action - but a couple of signals can't be caught or ignored at all.
Signals you'll actually use
| Signal | Number | Default action | Typical use |
|---|---|---|---|
SIGHUP |
1 | Terminate | Historically "terminal hung up"; commonly repurposed by daemons to mean "reload your config" |
SIGINT |
2 | Terminate | What Ctrl+C sends - "interrupt" |
SIGQUIT |
3 | Terminate + core dump | Ctrl+, similar to SIGINT but requests a core dump |
SIGKILL |
9 | Terminate | Immediate, unconditional termination - cannot be caught, blocked, or ignored |
SIGTERM |
15 | Terminate | The polite way to ask a process to exit - the default signal kill sends |
SIGSTOP |
19 | Stop | Pause the process - cannot be caught or ignored, like SIGKILL's "pause" counterpart |
SIGCONT |
18 | Continue | Resume a stopped process |
SIGUSR1 / SIGUSR2 |
10 / 12 | Terminate | No fixed meaning - reserved for applications to define their own use |
List every signal name and number a system supports with kill -l.
SIGTERM vs. SIGKILL
This is the distinction that matters most in practice. SIGTERM asks a
process to shut down and lets it clean up first - close file handles,
flush buffers, finish an in-flight request, remove a lock file. SIGKILL
gives the process no choice or opportunity to react at all; the kernel
just removes it. Because a killed process can't run its own cleanup code,
SIGKILL should be a last resort for something that's genuinely hung, not
a routine way to stop a service - a database killed with SIGKILL
mid-write is a much more likely source of corruption than one given a
chance to shut down cleanly with SIGTERM.
This is also why systemctl stop sends SIGTERM first, waits a
configurable timeout, and only escalates to SIGKILL if the process
hasn't exited by then - see
systemd and Services.
Sending signals
kill 1234 # SIGTERM to PID 1234 (the default signal)
kill -9 1234 # SIGKILL, by number
kill -SIGKILL 1234 # SIGKILL, by name
kill -HUP 1234 # ask a daemon to reload config, if it supports it
killall nginx # signal every process matching a name
pkill -f "python worker" # signal by matching the full command line
Handling signals in scripts
Bash scripts can intercept signals with trap, useful for cleanup before
exiting:
#!/usr/bin/env bash
cleanup() {
echo "cleaning up temp files"
rm -f /tmp/mylock
}
trap cleanup EXIT SIGINT SIGTERM
touch /tmp/mylock
sleep 60
Here, cleanup runs whether the script finishes normally, is interrupted
with Ctrl+C, or receives SIGTERM - but not if it's killed with
SIGKILL, since that signal never reaches the process to be trapped. See
Shell Scripting for more on trap and
script-level error handling.
Job control and signals
Suspending a foreground job with Ctrl+Z sends it SIGTSTP, a catchable
variant of SIGSTOP; resuming it with fg or bg sends SIGCONT. See
Job Control for the full set of foreground/
background job commands these signals sit behind.