Processes and jobs
pkill
Send a signal (TERM by default) to every process whose name or command line matches a pattern.
pkill [-SIGNAL] [OPTION...] PATTERN
pkill is pgrep that signals instead of printing: the same regular-expression match on the
process name (or on the full command line with -f) and the same filters (-u, -P, -n,
-x, -F). The default signal is TERM; give another as -HUP, -9 or --signal KILL.
Its strength is also its danger: a pattern is a regular expression matched anywhere in the
name, and it hits every matching process you own (all of them, as root). pkill ssh also hits
sshd and ssh-agent. The safe habit is to run the same arguments through pgrep -a first,
check the list, then press up-arrow and change pgrep -a to pkill.
pkill prints nothing by default; -e reports each process it signaled. Its exit status is 0
if at least one process matched and 1 if none did, which scripts can treat as "was it running?".
Compared with killall, pkill matches patterns where killall matches whole names, and its
options are the same on every Linux system because both tools come from procps.
Examples
Stop all processes with a given name
sleep 300 & sleep 600 &
pkill sleep
wait
pgrep sleep || echo "no sleep processes left"
no sleep processes left
Every process whose name contains sleep gets TERM. pkill is silent; the follow-up
pgrep finds nothing and exits 1, so the message prints.
Report what was signaled
sleep 300 & sleep 600 &
pkill -e sleep
sleep killed (pid 1797) sleep killed (pid 1798)
-e (--echo) prints the name and PID of each process signaled. Worth adding whenever
pkill runs from a script, so the log shows what it did.
Match the exact process name
sleep 300 &
pkill -x slee; echo "slee: exit $?"
pkill -e -x sleep
slee: exit 1 sleep killed (pid 1800)
Without -x, slee would have matched sleep. With it, the whole name must match; no
process is named exactly slee, so nothing is signaled and the exit status is 1.
Tell a daemon to reload with HUP
#!/bin/bash
trap 'echo "HUP received, reloading config"' HUP
while :; do sleep 0.1; done
chmod +x daemon.sh
./daemon.sh &
sleep 0.3
pkill -HUP -x daemon.sh
sleep 0.3
HUP received, reloading config
For a script started through its #! line, the process name is the script's file name,
so -x daemon.sh matches it. -HUP (or --signal HUP) replaces the default TERM; the
script's trap runs and it keeps going. pkill -HUP nginx and pkill -USR1 rsyslogd work
the same way.
Kill processes that ignore TERM
bash -c 'trap "" TERM; sleep 300' &
sleep 0.2
pkill -e -x sleep
sleep 0.2
pgrep -a -x sleep
pkill -9 -e -x sleep
sleep killed (pid 1814) 1814 sleep 300 sleep killed (pid 1814)
The child shell ignores TERM, and an ignored signal stays ignored in the programs it
starts, so sleep survives the first pkill (which still reports it as signaled). -9
sends KILL, which cannot be ignored.
The classic mistake, pkill -f killing its own shell
trap 'echo "outer shell: got TERM as well"' TERM
bash -c 'sleep 300 & pkill -f "sleep 300"; echo "never printed"'
echo "inner shell exit status: $?"
Terminated outer shell: got TERM as well inner shell exit status: 143
-f matches full command lines, and the inner shell has sleep 300 in its own command
line, so pkill terminates it before its echo; the outer shell reports Terminated and
status 143. The outer shell matched too; only its trap kept it alive to say so. A script named backup.sh that
runs pkill -f backup to stop an earlier run kills itself the same way.
Exclude your own shell with -A
sleep 300 &
pkill -e -A -f 'sleep 300'
echo "still here"
sleep killed (pid 1824) still here
-A (--ignore-ancestors, procps 4) skips the processes in pkill's own ancestry, so only
the sleep is signaled. On systems without -A, make the pattern specific enough not to
match the calling command, or use a PID file.
Signal only one user's processes
sleep 300 &
pkill -e -u dev sleep
pkill -u root sshd; echo "exit status: $?"
sleep killed (pid 1827) pkill: killing pid 8 failed: Operation not permitted exit status: 1
-u filters by effective user. The second command matches root's sshd but dev may not
signal it: pkill prints the permission error and, having signaled nothing, exits 1. As root, pkill -u alice ends all of
a user's processes, which is how to clean up after a stuck login.
Signal only the newest match
sleep 300 & sleep 301 & sleep 302 &
pkill -n -e sleep
pgrep -a sleep
sleep killed (pid 1833) 1831 sleep 300 1832 sleep 301
-n picks the most recently started match and -o the oldest. Useful when you just started
a second copy by mistake and want to stop only that one.
Signal the process named in a PID file
sleep 300 &
echo $! > app.pid
pkill -e -F app.pid sleep
sleep killed (pid 1836)
-F FILE reads the PID from a file, as daemons write them to /run/NAME.pid. Adding a
pattern means the PID is signaled only if it still belongs to a sleep, which guards
against a stale file whose PID has been reused by something else.
Stop the children of a process
(sleep 300 & sleep 400 & wait) &
sleep 0.2
pkill -e -P $! sleep
sleep killed (pid 1840) sleep killed (pid 1841)
-P PPID selects processes by parent PID; the pattern narrows it to the sleep children
(leave the pattern out to match every child). The subshell's two sleep processes are stopped and the subshell's wait returns.
Exit status when nothing matches
pkill nginx
(no output)
No output and exit status 1. In a script that should not fail when the program is already
stopped, write pkill nginx || true.
Common pitfalls
pkill -f patternfrom a script orbash -ckills the caller when its own command line matches, as shown above. Use-A, a narrower pattern, or-xon the process name.Unanchored patterns:
pkill sshhitssshd(and can cut your own SSH session) andssh-agent. Check withpgrep -afirst and use-xwhen you mean one exact name.Running
pkill -9as the first move. Processes get no chance to clean up; send the defaultTERM, give them a few seconds, and only then use-9.As root, a careless pattern matches system processes too. Add
-u USERto keep the blast radius to one account.Signal names with the
-prefix are fine (pkill -HUP x), butpkill -s HUP xis wrong:-smeans session ID. Use--signal HUPfor the long form.
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).
macOS and FreeBSD
pkillshare the core options with Linux (-f,-x,-u,-n,-o,-P,-SIGNAL);-Aand the--signallong form are procps additions. BSDpkillexcludes its own ancestors by default, so the self-kill pitfall mostly bites on Linux.
Options worth knowing
A selection, described in our own words. For the full list, see pkill(1) or pkill --help.
| Option | What it does |
|---|---|
-e | Print the name and PID of each process signaled. |
-f | Match the pattern against the full command line, not just the name. |
-x | Require the pattern to match the whole name (or command line with -f). |
-i | Match case-insensitively. |
-c | Print how many processes matched. |
-n | Signal only the most recently started match. |
-o | Signal only the least recently started match. |
-O SECS | Match only processes running longer than SECS seconds. |
-u USERS | Match only processes with these effective users. |
-U USERS | Match only processes with these real users. |
-P PPIDS | Match only children of these parent PIDs. |
-g PGIDS | Match only processes in these process groups. |
-s SIDS | Match only processes in these sessions (not a signal option). |
-t TTYS | Match only processes on these terminals. |
-F FILE | Read the PIDs to signal from FILE. |
-A | Never signal pkill's own ancestors, such as the calling shell. |
--signal SIGNAL | Send SIGNAL, by name or number, instead of TERM. |
-9 | Send KILL, which cannot be caught or ignored. |
-KILL | Send KILL by name. |
-TERM | Send TERM, the default. |
-HUP | Send HUP, usually a request to reload configuration. |
-INT | Send INT, the same as pressing Ctrl-C. |
-USR1 | Send USR1, whose meaning each program defines. |
-STOP | Pause the matching processes. |
-CONT | Resume paused processes. |
Related
pgrepPrint the PIDs of processes whose name (or full command line) matches a pattern, with filters by user, parent and age.killSend a signal to processes by PID or job number; by default TERM, which asks a process to exit.killallSend a signal (TERM by default) to all processes running a program with the given name.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.- 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.