⚙️ Lesson 7: Processes: What Is Running and How to Stop It

See what your computer is doing right now, run things in the background, and stop a program politely or firmly

Video: Processes (Linux 101 video)
Prefer to watch? This short video runs the lesson's main commands on a real Ubuntu 24.04 machine, with on-screen captions and no voiceover. Click to play, or watch it on YouTube.

What is a process?

Every time a program runs, Linux starts a process: one running copy of that program. Run the same program three times and you have three processes. Each process has:

Every process on a Linux machine has a parent, all the way back to process number 1, the very first one. On a normal Linux computer that is the system manager (lesson 8). In the practice container from lesson 1 it is simply the bash shell you are typing in, because a container starts from your shell and nothing else. That is why a container shows only a handful of processes, where a real machine shows hundreds.

Open your practice machine and follow along. Everything below was run on a real Ubuntu 24.04. Your PID numbers will be different on your machine, and that is fine.

See your processes with ps

ubuntu@practice:~$ ps
    PID TTY          TIME CMD
      1 pts/0    00:00:00 bash
      9 pts/0    00:00:00 ps
ubuntu@practice:~$ ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
ubuntu         1       0  0 14:22 pts/0    00:00:00 /bin/bash
ubuntu        10       1  0 14:22 pts/0    00:00:00 ps -f
ubuntu@practice:~$ sleep 300 &
[1] 11
ubuntu@practice:~$ ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
ubuntu         1       0  0 14:22 pts/0    00:00:00 /bin/bash
ubuntu        11       1  0 14:22 pts/0    00:00:00 sleep 300
ubuntu        12       1  0 14:22 pts/0    00:00:00 ps -f
ubuntu@practice:~$ jobs
[1]+  Running                 sleep 300 &

Foreground, background and suspended

A program you start normally runs in the foreground: you wait until it finishes, and the prompt only comes back afterwards. You can move programs between foreground and background:

ubuntu@practice:~$ fg
sleep 300
^Z
[1]+  Stopped                 sleep 300
ubuntu@practice:~$ jobs
[1]+  Stopped                 sleep 300
ubuntu@practice:~$ bg
[1]+ sleep 300 &
ubuntu@practice:~$ jobs
[1]+  Running                 sleep 300 &
ubuntu@practice:~$ kill %1
ubuntu@practice:~$ jobs
[1]+  Terminated              sleep 300

Everything running: ps aux

ubuntu@practice:~$ sleep 500 &
[1] 13
ubuntu@practice:~$ sleep 600 &
[2] 14
ubuntu@practice:~$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
ubuntu         1  0.3  0.0   4600  4116 pts/0    Ss   14:22   0:00 /bin/bash
ubuntu        13  0.0  0.0   2708  1528 pts/0    S    14:22   0:00 sleep 500
ubuntu        14  0.0  0.0   2708  1556 pts/0    S    14:22   0:00 sleep 600
ubuntu        15  0.0  0.0   7904  3980 pts/0    R+   14:23   0:00 ps aux
ubuntu@practice:~$ pgrep -a sleep
13 sleep 500
14 sleep 600

ps aux lists all the processes on the machine, not only the ones in your terminal. The letters are three options together: a for processes of all users, u for a user-friendly layout with CPU and memory, and x for processes that have no terminal. The columns:

On a real machine ps aux prints hundreds of lines, and you find the one you want with grep (lesson 4) and a pipe (lesson 11). A quicker way to find a process by name is pgrep -a: pgrep -a sleep printed the PID and command of each sleep: 13 and 14.

A live view: top

ps takes a photograph. top is a live video, updating every few seconds, sorted with the busiest processes first. It takes over the whole terminal, so we ran it once in "batch" mode (-b, one round with -n 1) to capture a snapshot:

ubuntu@practice:~$ top -b -n 1
top - 14:22:05 up 3 days,  4:29,  0 user,  load average: 0.33, 0.51, 0.62
Tasks:   4 total,   1 running,   3 sleeping,   0 stopped,   0 zombie
%Cpu(s):  4.8 us,  2.4 sy,  0.0 ni, 92.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :  31778.5 total,  10952.0 free,   5850.2 used,  14886.0 buff/cache
MiB Swap:   8192.0 total,   8192.0 free,      0.0 used.  25928.3 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
      1 ubuntu    20   0    4600   4080   3476 S   0.0   0.0   0:00.05 bash
     13 ubuntu    20   0    2708   1656   1556 S   0.0   0.0   0:00.00 sleep
     14 ubuntu    20   0    2708   1652   1556 S   0.0   0.0   0:00.00 sleep
     17 ubuntu    20   0    8732   5064   3004 R   0.0   0.0   0:00.00 top

The top part is a summary of the whole machine:

The table lists processes. PID and USER you know. %CPU and %MEM show what each one uses, and TIME+ the total processor time. S is the state again, and COMMAND the name.

In real, interactive top, press q to quit, k to kill a process (it asks for the PID), h for help, and the Shift+M and Shift+P keys to sort by memory or by processor use (from the documentation, not run here). A friendlier look-alike called htop can be installed with apt (lesson 6).

Stopping a process: kill and signals

Despite its name, kill does not necessarily kill. It sends a signal: a short message to a process. The signal decides what happens. Two matter most:

ubuntu@practice:~$ kill -l 15
TERM
ubuntu@practice:~$ kill -l 9
KILL
ubuntu@practice:~$ kill 13
ubuntu@practice:~$ jobs
[1]-  Terminated              sleep 500
[2]+  Running                 sleep 600 &
ubuntu@practice:~$ kill -9 14
ubuntu@practice:~$ jobs
[2]+  Killed                  sleep 600
ubuntu@practice:~$ pgrep -a sleep
ubuntu@practice:~$ echo $?
1

So why have two? Because a program can ignore TERM, as this example shows. We start a loop that is told to ignore it:

ubuntu@practice:~$ sh -c 'trap "" TERM; while true; do sleep 1; done' &
[1] 18
ubuntu@practice:~$ ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
ubuntu         1       0  0 14:22 pts/0    00:00:00 /bin/bash
ubuntu        18       1  0 14:23 pts/0    00:00:00 sh -c trap "" TERM; while tr
ubuntu        19      18  0 14:23 pts/0    00:00:00 sleep 1
ubuntu        20       1  0 14:23 pts/0    00:00:00 ps -f
ubuntu@practice:~$ kill 18
ubuntu@practice:~$ ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
ubuntu         1       0  0 14:22 pts/0    00:00:00 /bin/bash
ubuntu        18       1  0 14:23 pts/0    00:00:00 sh -c trap "" TERM; while tr
ubuntu        21      18  0 14:23 pts/0    00:00:00 sleep 1
ubuntu        22       1  0 14:23 pts/0    00:00:00 ps -f
ubuntu@practice:~$ kill -9 18
ubuntu@practice:~$ ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
ubuntu         1       0  0 14:22 pts/0    00:00:00 /bin/bash
ubuntu        24       1  0 14:23 pts/0    00:00:00 ps -f
[1]+  Killed                  sh -c 'trap "" TERM; while true; do sleep 1; done'

kill 18 sent TERM, and nothing happened: process 18 is still listed afterwards (the sleep 1 under it is just the loop's helper, and it gets a new number every second). Only kill -9 18 worked: the next ps -f shows it is gone, and the shell reported Killed.

The rule that follows is: **always try plain kill first**, and give the program a moment. Use kill -9 only when a process truly will not stop. Killing a program with -9 skips its cleanup, which can leave half-written files, so never do it casually to something important like a database.

Two more things to know. You can only kill your own processes; only the administrator can kill other people's (lesson 5, and the same ownership idea). And pkill NAME kills by name instead of by number, so pkill sleep ends every sleep (from the documentation, not run here). Check what matches with pgrep -a NAME first.

Why does Linux have two ways to stop a program?<br>
Because some processes only understand <span class="command">kill -9</span>.

🧪 Try it yourself

1. Start two background sleep jobs, one for 400 seconds and one for 500. List them with jobs and with pgrep -a sleep. 2. End the first with kill %1. Check with jobs. 3. Start another sleep 600 in the foreground (without &), suspend it with Ctrl+Z, then let it carry on in the background with bg. 4. Run ps -f and find the PPID of your sleep. Which process is its parent? 5. Run top -b -n 1 and read the %Cpu(s) line. How much of the processor is idle? 6. Run sh -c 'trap "" TERM; while true; do sleep 1; done' &. Try kill on it, check it is still there, then finish it with kill -9.

The cheat sheet

← Lesson 6 · ↑ All lessons · Lesson 8: Services and Logs: Starting, Stopping and Reading What Your System Says →