Processes and jobs · bash builtin
kill
Send a signal to processes by PID or job number; by default TERM, which asks a process to exit.
kill [-s SIGNAL | -SIGNAL] PID|%JOB... or kill -l [SIGNAL|STATUS]
Despite the name, kill sends signals, and only some of them end a process. The default is
TERM (15), a polite request: the program can catch it, flush its files, remove its PID file
and exit. KILL (9) cannot be caught or ignored; the kernel removes the process at once, with
no cleanup. Other everyday signals: HUP (1) makes many daemons reload their configuration,
INT (2) is what Ctrl-C sends, STOP and CONT pause and resume, and USR1/USR2 mean
whatever the program defines (log rotation, a status dump).
The usual sequence for a stuck process is kill PID, wait a few seconds, check with kill -0
PID, and only then kill -9 PID. Going straight to -9 leaves temp files, lock files and
half-written data behind.
In bash, kill is a builtin, which is why it understands job specs like %1 and works even
when the process table is full and no new process can start. There is also a standalone
/bin/kill (from procps on Linux) with a few extra options. To kill by name rather than PID,
use pkill or killall. When a process dies from a signal, the shell reports its exit
status as 128 plus the signal number: 143 for TERM, 137 for KILL.
Examples
Ask a process to terminate
sleep 300 &
kill $!
wait $!
echo "exit status: $?"
exit status: 143
$! is the PID of the most recent background job. kill sends TERM; wait collects the
job's status, 143 = 128 + 15, meaning "killed by signal 15".
List the signal names and numbers
kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
Every signal Linux defines. Numbers 1 to 15 are the same on every Unix-like system; the
higher ones differ (USR1 is 30 on macOS), so use names in scripts. kill -l also works
with a name or number (kill -l 9 prints KILL).
Find out which signal killed a process
kill -l 143
kill -l 137
kill -l HUP
TERM KILL 1
Given an exit status above 128, bash's kill -l subtracts 128 and prints the signal name, so
a $? of 137 decodes to KILL (often the kernel's out-of-memory killer). Given a name, it
prints the number.
Kill a process that will not exit
bash -c 'trap "echo ignoring TERM" TERM; while :; do sleep 0.1; done' &
sleep 0.3
kill $!
sleep 0.3
kill -0 $! && echo "still running"
kill -9 $!
wait $!
echo "exit status: $?"
ignoring TERM still running /bin/bash: line 7: 1273 Killed bash -c 'trap "echo ignoring TERM" TERM; while :; do sleep 0.1; done' exit status: 137
The child traps TERM and keeps going. kill -0 sends no signal, only checks that the
process exists and you may signal it. kill -9 (-KILL) cannot be trapped; bash prints a
Killed notice for the job and the status is 137 = 128 + 9.
Check whether a process is still alive
sleep 300 &
pid=$!
if kill -0 "$pid" 2>/dev/null; then echo "$pid is running"; fi
kill "$pid"; wait "$pid"
kill -0 "$pid" 2>/dev/null || echo "$pid is gone"
1283 is running 1283 is gone
Signal 0 performs the existence and permission checks without delivering anything, so the exit status answers "is this PID alive and mine?". Note it also fails for a live process owned by another user.
Tell a daemon to reload its configuration
#!/bin/bash
trap 'echo "reloading config"' HUP
trap 'echo "shutting down cleanly"; exit 0' TERM
echo "started as $$"
while :; do sleep 0.1; done
bash daemon.sh &
sleep 0.3
kill -HUP $!
sleep 0.3
kill $!
wait $!; echo "exit status: $?"
started as 1285 reloading config shutting down cleanly exit status: 0
The script handles HUP by reloading and TERM by cleaning up and exiting 0, exactly what
nginx, sshd and most daemons do. -HUP, -s HUP and -1 are equivalent spellings.
Pause and resume a process
sleep 300 &
sleep 0.1
kill -STOP $!
ps -o pid,stat,args -p $!
kill -CONT $!
ps -o pid,stat,args -p $!
PID STAT COMMAND
1295 T sleep 300
PID STAT COMMAND
1295 S sleep 300 STOP freezes the process (state T) without ending it, CONT resumes it (back to S,
sleeping). Useful to pause a CPU-heavy job temporarily; like KILL, STOP cannot be caught.
Kill background jobs by job number
sleep 300 &
sleep 600 &
jobs
kill %1 %2
wait
jobs
[1]- Running sleep 300 & [2]+ Running sleep 600 & [2] Terminated sleep 600
%1 and %2 refer to entries in the shell's job table, so you do not need the PIDs. Only
the builtin kill understands % job specs; /bin/kill %1 does not. After wait, the job
table is empty.
Kill a whole process group
set -m
sleep 300 | sleep 301 &
pgid=$(jobs -p %1)
pgrep -a -g "$pgid"
kill -- -"$pgid"
wait
pgrep -c -g "$pgid"
1302 sleep 300 1303 sleep 301 0
With job control on (set -m), each job gets its own process group, whose ID is the PID of
its first process; jobs -p prints it. A negative PID signals every process in the group,
and -- stops -123 being read as a signal option. Afterwards pgrep -c finds nothing,
prints 0 and exits 1. This is how to stop a pipeline or a script together with everything
it started.
See which kill you are running
type -a kill
/bin/kill -L | head -3
kill is a shell builtin kill is /usr/bin/kill kill is /bin/kill 1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS 8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM 15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN
type -a shows the bash builtin first, then the procps programs on PATH. The external
/bin/kill has extras such as -L (a signal table) and --timeout, but the builtin is what
runs when you type kill.
Signal a PID that does not exist
kill 99999
/bin/bash: line 1: kill: (99999) - No such process
No such process and exit status 1. A script that kills a PID read from a stale PID file
should expect this, and treat it as "already stopped".
Common pitfalls
Reaching for
kill -9first. The process gets no chance to clean up: temp files stay, locks stay held, buffered writes are lost and child processes may be orphaned. SendTERM, wait, and escalate only if needed.Trusting a PID file blindly. PIDs are reused, so after a crash the number may belong to an unrelated process. Check what it is first (
ps -p "$pid" -o args=) or usepkill -F pidfile, which also checks.Writing
kill -15 -1orkill -9 -1:-1as a PID means every process you are allowed to signal, which ends your whole session (as root, nearly everything).Expecting
killto wait. It returns as soon as the signal is sent, before the process has exited. In a script, follow it withwait "$pid"(for your own children) or poll withkill -0.Using signal numbers above 15 in portable scripts.
USR1,CHLDandSTOPhave different numbers on Linux and macOS; use names.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
The signals 1 to 15 have the same numbers everywhere; above that they differ (
USR1is 10 on Linux and 30 on macOS,STOP19 vs 17). Names are portable.procps
/bin/killadds options the bash builtin lacks, such as-L(signal table) and--timeout(send a follow-up signal after a delay). macOS/bin/killhas neither.
Options worth knowing
A selection, described in our own words. For the full list, see kill(1).
| Option | What it does |
|---|---|
-s SIGNAL | Send SIGNAL, given by name (TERM, HUP) or number. |
-n SIGNUM | Send the signal with number SIGNUM (bash builtin). |
-l | List signal names, or translate a name, number or exit status. |
-L | List signal names and numbers as a table (bash builtin and procps kill). |
-9 | Send KILL, which cannot be caught or ignored. |
-15 | Send TERM, the default polite termination request. |
-1 | Send HUP, often used to make a daemon reload its configuration. |
-0 | Send no signal; only check that the process exists and may be signaled. |
-KILL | Send KILL by name (same as -9). |
-TERM | Send TERM by name (same as -15). |
-HUP | Send HUP by name (same as -1). |
-INT | Send INT, the signal Ctrl-C sends (same as -2). |
-QUIT | Send QUIT, the signal Ctrl-\ sends; many programs dump core on it. |
-USR1 | Send USR1, whose meaning each program defines (often reopen logs). |
-STOP | Pause the process; it cannot be caught. |
-CONT | Resume a stopped process. |
Related
pkillSend a signal (TERM by default) to every process whose name or command line matches a pattern.killallSend a signal (TERM by default) to all processes running a program with the given name.pgrepPrint the PIDs of processes whose name (or full command line) matches a pattern, with filters by user, parent and age.psPrint a snapshot of running processes, with the columns, filters and sort order you choose.timeoutRun a command with a time limit, and kill it if it is still running when the time is up.waitWait for background jobs of the current shell to finish, and return their exit status.jobsList the background and stopped jobs of the current shell, with their job numbers and state.trapRun a command when the shell receives a signal or exits, typically to clean up temporary files.- Traps and signalsRunning cleanup code with trap on EXIT, handling INT and TERM, the ERR pseudo-signal, and the timing and scoping rules that trip people up.
- Exit codesWhat exit statuses mean, how $? works, the reserved values 126, 127 and 128+N, PIPESTATUS, and how to choose codes for your own scripts.