Stopping Things: kill and Signals

kill sends a process a signal: plain kill sends TERM, a polite request to finish up and stop; kill -KILL ends a process that ignores it; pgrep -af and pkill -f find and stop processes by name; and Ctrl+C sends INT to the program in front of you.

Journeyman · Unix · Linux · Updated

After this lesson you can

  • Stop a process by its PID with kill, and send -KILL only when the polite -TERM doesn't work
  • Name the signal that Ctrl+C, kill and kill -KILL send, and what a program can do with each
  • Find and stop processes by name with pgrep -af and pkill -f, checking with pgrep first

Key takeaways

  • kill PID sends the process TERM, a signal that means: please finish up and stop. Most programs stop at once.
  • A program can catch TERM to save its work, or ignore it. kill -KILL (or kill -9) can't be caught: the process ends on the spot, with no chance to clean up.
  • Send TERM first, check with ps -p PID, and send KILL only when the process is still there.
  • pgrep -af NAME lists matching processes and pkill -f NAME stops them. Look with pgrep before you stop with pkill.
  • Ctrl+C sends INT, the interrupt signal, to the program running in front of you in that terminal.

A program has frozen, and its window won't close. A script you started an hour ago is stuck in a loop, draining the battery. On a server, a copy of a website that crashed halfway still holds on to its address, so the new copy can't start. Ctrl+C stops only the program running in front of you, in your own terminal. For everything else there's kill: the terminal's Force Quit, which administrators use every week and developers reach for whenever a test or a server won't stop.

These examples use the practice folder and the two terminals from What's Running: ps, top and htop. Add one more program, stubborn.sh, which refuses to stop when it's asked nicely:

cd ~/terminal-practice/processes
printf '%s\n' '#!/usr/bin/env bash' '# stubborn.sh: ignores a polite request to stop.' "trap 'echo \"Not now, I am busy.\"' TERM" 'while true; do sleep 1; done' > stubborn.sh
chmod +x stubborn.sh

kill sends a signal

Asking someone to leave a party can go two ways. You can tap them on the shoulder and say it's time to go, so they find their coat and say goodbye; or security can carry them out. Processes get the same two choices through signals: short messages the system delivers to a process. kill sends one, and despite its name, the one it sends unless you ask for another is the polite one, TERM (for terminate): "please finish up and stop".

Start the alarm in the second terminal with ./alarm.sh. It prints BEEP every second. In the first terminal, find its PID:

ps aux | grep alarm
sam         2565  0.0  0.0   4952  3784 pts/5    S+   07:33   0:00 bash ./alarm.sh
sam         2648  0.0  0.0   4132  2432 pts/2    S+   07:33   0:00 grep --color=auto alarm

Then send it TERM. kill prints nothing when it works:

kill 2565

The second terminal shows what happened. The alarm stopped, and bash reports how it ended:

BEEP
BEEP
BEEP
BEEP
BEEP
Terminated                 ./alarm.sh

When TERM isn't enough: -KILL

A program can catch TERM and run code of its own first: save the file you were editing, or delete its temporary files, the way trap did in Cleaning Up: trap and mktemp. It can also ignore it, and stubborn.sh does: its trap line answers TERM with a message and carries on. Start it in the second terminal with ./stubborn.sh, find its PID the same way (here, 2676), and ask it to stop:

kill 2676

The second terminal answers Not now, I am busy., and the program keeps going. ps -p (read "the process with this PID") lists only that one process, so you can check:

ps -p 2676
    PID TTY          TIME CMD
   2676 pts/5    00:00:00 bash

Still there. Now send KILL, the one signal no program can catch or ignore. The system ends the process on the spot:

kill -KILL 2676
ps -p 2676
    PID TTY          TIME CMD

Only the header: it's gone, and the second terminal says Killed. You'll often see this written kill -9, the signal's number. Why not use it every time? Because a killed program gets no chance to clean up: a half-saved file stays half saved, and temporary files stay behind. The habit administrators use is TERM first, a few seconds to finish, a check with ps -p, and KILL only when it's still there.

By name: pgrep and pkill

Looking up a PID every time gets old, and it changes every time the program starts. pgrep finds processes by name and prints their PIDs; -a adds each one's command. A script runs as bash, so add -f to match against the whole command line, script name included. Start the alarm again in the second terminal, then:

pgrep -af alarm
2781 bash ./alarm.sh

On a Mac, write pgrep -lf alarm instead: there, -a means something else.

pkill takes the same words and sends TERM to every process that matches. Afterward, pgrep finds nothing and prints nothing, and the second terminal says Terminated:

pkill -f alarm
pgrep -af alarm

Choose the words with care: pkill -f alarm stops every process with alarm anywhere in its command line, such as an editor with alarm-notes.txt open. That's why pgrep comes first, with the same words: it shows exactly what pkill would stop. You can signal only your own processes; another user's or the system's need sudo (sudo and Who Owns a File), and on a computer you share, ask whoever looks after it before you reach for that.

What Ctrl+C really sends

Ctrl+C sends a signal too: INT (for interrupt), to the program running in front of you in that terminal. Like TERM, a program can catch it, and trap cleaned up after Ctrl+C that way. Every signal has a name and a number, and kill -l (a lowercase L, for list) turns numbers into names:

kill -l 2 9 15
INT
KILL
TERM
Signal Number Sent by Can a program catch it?
INT 2 Ctrl+C Yes
TERM 15 kill, pkill Yes
KILL 9 kill -KILL, kill -9 No

You'll also see the names with SIG in front, such as SIGTERM: kill -TERM and kill -SIGTERM are the same. On a Mac, kill works the same way in zsh; only the messages in the second terminal are worded differently.

Try it in the terminal

Terminal Quest: Mission Control, goal 2: played right on the lesson page.

Launch day at Mission Control, and an alarm won't stop beeping. List what's running with ps, then stop the alarm with kill and its PID.

Check yourself

2 questions to try on the lesson page.

So what

kill is how you stop anything, anywhere, once you know its PID or its name: TERM first, so it can tidy up, and KILL only when it won't listen.

Key terms

Cheat sheets

Related