pkill Command: Tutorial & Examples
The daemon-administrator's hammer — signal a service by name without ever touching a PID.
What It Is
pkill is how grown-ups signal processes on a modern Linux box. You name what you want — nginx, java.*MyApp, "every child of PID 14021" — and pkill finds the matching PIDs in /proc and delivers a signal to each one. By default that signal is SIGTERM, the polite "please wrap up" — the same default kill sends when you give it a bare PID. pkill just spares you the PID-hunting step.
If you've read the pgrep page you already know the deepest fact about this command: pkill and pgrep are the same tool wearing two name tags. Every flag here works there. That symmetry is the whole point — it's what makes pkill the only safe scriptable kill-by-name on Linux: you preview with pgrep, swap one letter, execute with pkill. And if you've read kill, pkill sends the same signals (-TERM, -HUP, -9, -STOP) over the same kill(2) system call — it's pure sugar on top, and a much better sugar than killall for anything beyond a quick interactive cleanup.
This page is about the second job pkill quietly does better than anything else: daemon administration. pkill -HUP nginx, pkill -P $build_pid, pkill -f 'java.*MyApp' — these are the one-liners that real admins type ten times a day on a box that doesn't run systemd for everything.
Your First Look
Stop every running copy of nginx:
pkill nginx
No output on success — Unix convention, silence means it worked. Every process whose name contains nginx got SIGTERM. If nothing matched, pkill is also silent — but the exit code is 1, so scripts can tell.
Want a receipt? Add -e (echo) to see what was hit:
pkill -e nginx
nginx killed (pid 2341)
nginx killed (pid 2342)
nginx killed (pid 2343)
That's the whole shape of pkill: name in, signals out, three-line vocabulary worth memorising before we get any deeper:
pkill name # SIGTERM by name (substring match — careful)
pkill -HUP nginx # reload nginx config without restarting
pkill -9 stuck-thing # SIGKILL — only after SIGTERM was ignored
How I Use It
The shape of every pkill session is the same three steps, and once they're muscle memory you'll never kill $(pgrep ...) again.
Step 1: preview with pgrep -af. I almost never run pkill without first running the exact same command with pgrep and -a (list-full) instead. Same flags, same pattern. If pgrep -af 'java.*MyApp' shows me the three PIDs and command lines I expected, then pkill -f 'java.*MyApp' is safe. If it shows me seven PIDs — including some I didn't expect — I caught the mistake while I still had a job. The two lines differ by exactly one word, and that one word is the cheapest insurance policy in shell work.
Step 2: pick the right matcher. The default match is substring against the truncated 15-character process name stored in /proc/<PID>/stat — the same kernel limit that bites pgrep. Two flags fix almost every wrong-target problem: -x for exact name match, and -f to match against the full command line (/proc/<PID>/cmdline), which is the only way to single out one of fourteen java processes by what's after java on the command line. pkill ssh is a near-guaranteed lockout (substring matches sshd, ssh-agent, and your live ssh sessions); pkill -x ssh matches only the literal command ssh; pkill -f 'ssh holger@' targets one specific session.
Step 3: pick the right signal. Default is SIGTERM and that's almost always right. The two non-default signals worth typing reflexively are -HUP (daemon, reread your config) and — only after SIGTERM has been ignored for ten seconds — -9 (SIGKILL, the kernel yanks the process out of existence with no cleanup). See kill for the full signal catalogue; everything that works there works here.
Pro Tip
the preview habit is the magic of this command. Type
pgrep -af 'pattern'first, read what would be hit, then press up-arrow and changepgrep -aftopkill -f(orpkill -HUP -f, etc.) — same pattern, same flags.pkillandpgrepare the same binary wearing different name tags, which is why the flags line up perfectly. Build this habit and you stop being scared of broad-match kills.
The Flags Explained
Every pkill flag, grouped by what it actually does for you. The catalogue is identical to pgrep; the only differences are output flags (which only make sense on pgrep) and -v (deliberately disabled here so you can't accidentally signal the inverse of your match).
Matching: how the pattern is compared.
-f/--full— match against the full command line (/proc/<PID>/cmdline), not the truncated 15-character name. The flag that unlocks targeting one specific Java app among fourteenjavaprocesses. The pattern is an extended regex, sopkill -f 'java.*MyApp'works.-x/--exact— exact match, no substring.pkill -x sshmatches only the literal namessh, leavingsshdandssh-agentalone.-i/--ignore-case— case-insensitive match.
Filtering: AND-narrow the candidate set. Every filter you add must also match — pkill -u root sshd is "named sshd AND owned by root."
-u euid,.../-U uid,...— by effective or real user ID.pkill -u alice(with no name) signals every processaliceowns.-g pgid,.../-G gid,...— by process group or real group ID. Group0resolves topkill's own group.-P ppid,.../--parent— match only children of the given parent PID. The cleanest "kill this whole subtree" without invoking shell job control. See Reading by Example.-s sid,.../--session— by session ID.-t tty,.../--terminal— by controlling tty (e.g.-t pts/0). Useful for "kill everything that's still attached to that disconnected serial line."-r state/--runstates— by run state:D,R,S,Z,T,I. (Note:D-state processes can't actually be signaled — seekillGotchas.)-O secs/--older— only processes older than N seconds.-n/-o— keep only the newest or oldest match.pkill -n -f 'java.*'kills only the youngest matching Java.-A/--ignore-ancestors— ignorepkill's own ancestor chain (shells,sudo). Saves you from abashscript that accidentally matches itself via-f.-F file/--pidfile— read PIDs from a pidfile, the daemon integration. Pair with-Lto fail unless the pidfile is locked (proves the daemon is alive).--cgroup name/--ns pid/--nslist— modern systemd world: filter by cgroup v2 or by sharing a namespace with another PID. The bridge from old-school name matching to the container era.
Signal & delivery: what to send and how.
-SIGNAL/-s SIGNAL/--signal SIGNAL— send the named signal instead ofSIGTERM.pkill -HUP nginx,pkill -USR1 nginx(log rotate),pkill -9 stuck(last resort),pkill -STOP 1234(freeze). Any signal fromkill -l.-e/--echo— printname killed (pid N)for each process signaled. The receipt flag. This is thepkill-only sibling ofpgrep's-a.-c/--count— print how many processes matched (still sends the signal). Exit code is non-zero on count of 0.-q value/--queue— usesigqueue(3)instead ofkill(2)and attach an integer payload the receiver can read viasiginfo_t. The bridge to real-time signals and the most obscure flag here — almost nobody uses it, but if you're writing a daemon that listens for typed messages, this is how you send them.-H/--require-handler— only signal processes that have a userspace handler installed for the signal being sent. Stops you sendingSIGUSR1to a process that would treat it as the default (terminate).
Warning
pkill sshon a remote box is the classic foot-gun. Substring match grabssshd(the daemon accepting your future logins),ssh-agent(holding your private keys), and every livesshsession including the one you're typing in. The connection drops mid-keystroke and you can't reconnect becausesshdis gone. Always preview withpgrep -af sshfirst, or usepkill -x sshdif you really mean only the daemon.
Reading It by Example
The handful of pkill recipes worth real muscle memory.
Preview, then execute — the one-letter swap:
pgrep -af 'java.*MyApp' # what would I hit?
pkill -f 'java.*MyApp' # same flags, same pattern, now do it
Read line 1. If it's right, hit up-arrow, change pgrep -af to pkill -f, run. Every time.
Tell a daemon to reload its config without restarting it:
pkill -HUP nginx
SIGHUP is the universal "reread your config file" message across well-behaved Unix daemons — nginx, apache, postfix, bind, haproxy, sshd all honor it the same way. This is the modern form of the kill-page idiom kill -HUP $(cat /var/run/nginx.pid) — same effect, no pidfile path, no cat subshell. On a systemd-managed service systemctl reload nginx is friendlier (and itself just sends SIGHUP under the hood), but on anything else, this one-liner is the standard.
Kill a whole subtree by parent PID — the cleanest cleanup move on a Linux box:
pkill -P 14021
Every direct child of PID 14021 gets SIGTERM. Lovely for a runaway worker pool whose supervisor is misbehaving, a build shell that spawned thirty subprocesses, or a bash script you launched in the background and want to stop without killing the shell itself. Combine with -f and a regex for finer targeting.
Rotate logs without restarting — the logrotate integration pattern:
pkill -USR1 nginx
nginx catches SIGUSR1 and re-opens its log files (so logrotate can move the old one out from under it). Application-specific — check the man page for whatever daemon you're poking — but the convention is broad.
Freeze, inspect, resume — the debugging dance:
pkill -STOP -f 'java.*MyApp' # freeze the app
strace -p $(pgrep -n -f 'java.*MyApp') # peek
pkill -CONT -f 'java.*MyApp' # let it run again
The process is frozen by the kernel, uses zero CPU, and you can attach strace, open /proc, look at file handles with lsof. No state lost.
Clean out a user's session:
pkill -u alice -KILL
No process name — with -u you can omit it entirely. Every process alice owns gets SIGKILL. The "force-logout" admin move.
Cheat Sheet
The lines worth memorising:
pgrep -af pattern(preview) →pkill -f pattern(execute) — the one-letter swap. The most important habit on this page.pkill -HUP daemon— reload config without restart. The daemon-admin one-liner.pkill -x exact-name— exact-name match, no substring lockouts.pkill -f 'regex'— match against the full command line.pkill -P PPID— kill every child of one parent.pkill -u user— every process owned by USER.pkill -e ...— echo what was killed (the receipt).pkill -9 thing—SIGKILL, last resort afterSIGTERMwas ignored.pkill -F /var/run/foo.pid— signal whatever's in a pidfile.
How You'll Actually Use It
Three contexts. Daemon administration on a server you own: pkill -HUP nginx after editing nginx.conf, pkill -USR1 nginx from your logrotate postrotate hook, pkill -F /run/myapp.pid -TERM from a deploy script. Interactive cleanup: you're at the shell, something is misbehaving, you type pgrep -af pattern, eyeball it, swap to pkill, done. Inside scripts and cron jobs: pkill is the only safe scriptable kill-by-name on Linux, because -f lets you anchor the match to something specific instead of gambling on a 15-character truncation, and the regex grammar lets you be as precise as you need to be.
A word on the modern world: if the thing you're signaling is managed by systemd — and on most distros that's now most daemons — the right tool is systemctl reload nginx, systemctl restart nginx, systemctl kill --signal=HUP nginx. systemd knows the cgroup, so it can't miss a child or hit the wrong process, and it handles the SIGTERM-then-SIGKILL escalation timeout for you. pkill is for everything that isn't a systemd unit: your own scripts, ad-hoc workers, builds that wedged, the Python repl you left running on a dev box, the Docker container's entrypoint that spawned a tree of helpers.
Gotchas
- The substring-match default is promiscuous.
pkill sshmatchessshd,ssh-agent, and every livesshsession — kicking yourself off the box you're working on. Use-xfor exact, or-fplus a tighter regex, or always preview withpgrepfirst. - The 15-character truncation. The kernel stores only 15 chars of the process name in
/proc/<PID>/stat.pkill my-very-long-daemonmatches nothing, butpkill -f my-very-long-daemonworks perfectly. When in doubt, use-f. - The pattern is an extended regex, not a glob.
pkill 'nginx|apache'works.pkill 'nginx*'does not mean what you think it means. pkill -vis deliberately disabled.pgrepaccepts-vto invert the match — and that's safe when you're just printing PIDs. Onpkill, inverting the match means "signal everything that doesn't match," which is the kind of mistake that ends careers. The maintainers disabled the short flag so you can't reach it by accident. The long form--inversestill works if you're sure.-fmatches your own command line too. Abashscript that contains the pattern in its source can match itself. Add-Ato ignore your own shell chain.- You can only signal what you own. Mortals can't signal root's processes; root can signal anyone.
pkillreturns non-zero silently when nothing was signaled — pair with-eif you want to know. - Exit code 1 = "no matches" or "signal failed." Both look the same to a script. If you need to distinguish, use
pgrep -cto count first. D-state processes can't be killed. Not even with-9. The process is asleep inside a kernel call (usually stuck disk or frozen NFS) and signals don't deliver until it wakes. Same gotcha askill.
History & Philosophy
pkill came from Solaris in 1996, alongside its twin pgrep, explicitly to retire the ps | grep | awk | kill pipeline that everybody was typing wrong. POSIX blessed them as the standardised name-based process tools — a fresh pair of names with no historical landmine, deliberately chosen to avoid the BSD-vs-Linux killall name collision (see the killall page for the full graybeard horror story). They landed in the Linux procps package soon after and are now in every distro by default.
The implementation detail worth knowing: pkill and pgrep (and pidwait, the newer "block until matching process exits" sibling) are one binary with three names. The executable inspects argv[0] to decide which mode to run in. Same code, same matching logic, same flag parser — that's why the flags line up perfectly, and it's why the preview-then-execute habit is so cheap to teach: it's literally one program reading the same arguments two different ways.
The deeper magic — same one running through top, ps, pgrep, killall — is that pkill isn't doing anything you couldn't do yourself. It opens /proc, iterates the numeric directories, reads each /proc/<PID>/stat (or cmdline when you pass -f), matches against your regex, then calls the kill(2) system call on every hit. The whole "signal by name" feature is twenty lines of shell over a /proc walk. What pkill adds is the flag vocabulary — -P, -u, -F, -x, --cgroup — and the pgrep sister-binary that lets you check your work for free. That combination is the actual feature.
See Also
- pgrep — the sister command; identical flags, prints PIDs instead of signaling. Always preview here first.
- kill — the primitive: one PID, one signal. Full signal catalogue lives there.
- killall — the older kill-by-name; exact-match by default, no preview sibling, BSD foot-gun history
- ps — the full process snapshot underneath
- top / htop — interactive, with a built-in
kkey to send signals - systemctl — the modern way to manage a known service on systemd-managed daemons
- nginx / apache — the canonical SIGHUP-reload targets
- strace — pair with
pkill -STOPto inspect a frozen process - xargs — the alternative when you want pgrep + a tool other than pkill
- signal / process / PID / /proc — the concepts behind the command
About to
pkillsomething on a production box and not 100% sure what will go down with it?CleverUptime keeps a live inventory of every process, PID, parent, and cgroup on every server you run — so you can see exactly what a
pkillpattern would match before you type it, and the moment a daemon you justpkill -HUP'd fails to come back, the alert is in your inbox with the recent log lines attached.Want to see your own server's health right now? One command, no signup, no install.