Sign in
← Terminal: getting oriented
3 min · easy · Lesson 3 of 5

Which processes are running: ps and pgrep

Count the copies of one process and save the number.

A service is acting up, and the first question is usually how many copies of it are running right now, and whether it's running at all. Maybe a worker crashed. Maybe a bad deploy left two of them. ps, pgrep and pidof give the answer, and kill stops the extra copy.

Where to practice

The examples below work in an ubuntu:24.04 container. You can bring up the same one yourself:

docker run --rm -it ubuntu:24.04 bash

Inside it, start three background processes to experiment on:

sleep 600 & sleep 600 & sleep 600 &

sleep 600 waits 600 seconds and does nothing. The & sends the command to the background, so the terminal is free for the next one right away. On macOS, ps and pgrep are different (from BSD); the difference is described in "Common mistakes".

Process and PID

A process is a running program. One program can run as several copies, and each copy is a separate process. A process has a PID (process ID) number: it's used to find the process and send it signals. Each process also has a parent, whose number is called the PPID.

What ps shows

ps without flags shows only the current terminal's processes:

ps
    PID TTY          TIME CMD
      1 pts/0    00:00:00 bash
      9 pts/0    00:00:00 sleep
     10 pts/0    00:00:00 sleep
     11 pts/0    00:00:00 sleep
     12 pts/0    00:00:00 ps

Our three sleep processes show up here because we started them from this same terminal. A server's services aren't started by your terminal, so they won't be in this list.

Every process in the system

To see everything running in the system, you need the -e flag (every), and -f (full) adds the UID, PPID and full command line columns:

ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  5 18:36 pts/0    00:00:00 bash
root           9       1  0 18:36 pts/0    00:00:00 sleep 600
root          10       1  0 18:36 pts/0    00:00:00 sleep 600
root          11       1  0 18:36 pts/0    00:00:00 sleep 600
root          13       1  0 18:36 pts/0    00:00:00 ps -ef

The CMD column shows the command along with its arguments. There's also ps aux from the BSD tradition: same processes, different columns (%CPU, %MEM, STAT). If a line gets cut off by the terminal width, add ww: ps -efww.

Searching by name with grep

On a live server, ps -ef prints hundreds of lines, and they get filtered with grep:

ps -ef | grep sleep
root           9       1  0 18:36 pts/0    00:00:00 sleep 600
root          10       1  0 18:36 pts/0    00:00:00 sleep 600
root          11       1  0 18:36 pts/0    00:00:00 sleep 600
root          15       1  0 18:36 pts/0    00:00:00 grep sleep

The fourth line is extra: grep sleep is itself running at the moment of the snapshot, and its own command line has the word sleep in it. If you count the lines with wc -l, you get 4 instead of 3.

Square brackets work around this:

ps -ef | grep '[s]leep' | wc -l
3

To grep, the pattern [s]leep means "the letter s, then leep", which matches sleep. But grep's own command line has [s]leep written with the brackets, and that doesn't match the pattern. The quotes keep the shell from treating the brackets as a filename pattern.

There's a second trap with grep on ps -ef. It searches the whole line, arguments included. A process like tail -f /tmp/sleep.txt will also match, even though it isn't sleep.

pgrep: searching without grep

pgrep searches processes by name and prints their PIDs. It doesn't include itself in the result:

pgrep sleep
9
10
11

Useful flags:

The difference between name and command line matters. A process's name is the program's name (up to 15 characters), say sleep or tail. The command line includes the arguments. Let's start tail on a file whose name contains sleep:

tail -f /tmp/sleep.txt >/dev/null &
pgrep -c sleep
3
pgrep -cf sleep
4

With -f, tail gets counted too, because the word is in its arguments. Without -f, its name tail doesn't match sleep.

If a program is a script starting with #!/bin/bash, the process name comes from the script file's name. In ps -ef such a process looks like /bin/bash /usr/local/bin/script-name, and pgrep script-name finds it.

pidof

pidof prints the PIDs of every process of a program on one line:

pidof sleep
11 10 9

You can count them with wc -w (words): pidof sleep | wc -w gives 3. pidof doesn't find scripts by default; that needs the -x flag. Another option on Linux: ps -C sleep shows processes with that name in regular ps format.

How to stop a process

kill PID sends the process a SIGTERM signal (number 15): "wrap up". A well-behaved program closes its files and exits on it.

kill 9
pgrep -c sleep
2

If a process doesn't respond to SIGTERM, there's kill -9 PID (SIGKILL). It can't be caught; the kernel kills the process immediately, and the program has no chance to clean up after itself. So -9 is a last resort, not the first step.

pkill works like pgrep, except instead of printing it sends a signal to every process it finds. It's easy to hit the wrong thing with it: pkill -f word stops everything with that word anywhere in its command line. Check who the pattern matched with pgrep -a first, and only then stop it.

Common mistakes

What you'll need for the tasks

Practice in your browser

Linux runs right here. Solve the task and we'll save your progress automatically.

01

How many tail processes

We started several tail processes in the background. Count how many instances are running right now and save the number to /tmp/answer.

{ i }

Go through it with an AI agent

The agent explains anything unclear in plain words, gives you 2 labs for this lesson and drills you on interview questions. $49 one-time, lifetime access.

Get access for $49

Tell the agent: use MCP izi, give me lesson terminal-basics-03-running-processes