Processes and Signals

K
Kai··4 min read

Everything "running" on Linux is a process. This article is a deep dive into processes: how to view them, how to run them in the background, and how to control/terminate them with signals — including the classic question: why kill -9 differs from a plain kill.

Processes and the parent-child relationship

Every process has a PID (Process ID) that identifies it, and a PPID (Parent PID) — the process that spawned it. All processes form a tree rooted at PID 1 (the init process, started first by the kernel; in a container it's usually the process you run).

View the current shell's processes:

ps
  PID TTY          TIME CMD
    1 ?        00:00:00 bash
    7 ?        00:00:00 ps

ps (no arguments) only shows the current shell's processes. To see every process on the system, use one of two common forms:

ps aux       # BSD style: includes %CPU, %MEM, user
ps -ef       # Unix style: includes PPID (parent)

ps -ef shows the PPID column — handy for tracing the parent-child tree:

UID    PID  PPID  CMD
root     8     1  sleep 300     ← PID 8, parent is PID 1

Watch "live" processes: top

ps is a snapshot of one moment. To watch dynamically (CPU, RAM updating continuously):

top

top lists the processes eating the most CPU/RAM, refreshing every few seconds (press q to quit). When a server is slow, this is the first command to see what's eating resources. htop (needs installing) is a prettier, easier-to-use version.

Quickly find a process by name:

pgrep -a nginx        # list PIDs + command lines of processes named nginx
ps aux | grep nginx | grep -v grep   # the manual way (excluding the grep command itself)

Run in the background: &, jobs, fg, bg

By default a command runs in the foreground — it holds the terminal until it finishes. Add & to run it in the background:

sleep 300 &
[1] 8        ← [job number] PID

The shell returns the prompt immediately. Managing background jobs:

jobs        # list this shell's background jobs
fg %1       # bring job 1 to the foreground
bg %1       # resume a stopped job in the background

Related shortcut: Ctrl + Z suspends the foreground process (turning it into a stopped job), then bg resumes it in the background or fg brings it back.

Background jobs are still tied to the terminal — close the terminal and they die with it (they receive a SIGHUP signal). To keep running after logout, use nohup command & or disown. But for a long-running service, the right way is systemd (Article 15), not nohup.

Signals: how to talk to a process

You control a process by sending it a signal — a short message from the kernel to the process. A process can "catch" some signals to handle them gracefully (save data, close files) before exiting. A few important signals:

Signal     Num  Meaning                          Catchable/ignorable?
─────────────────────────────────────────────────────────────────
SIGINT     2    interrupt (this is Ctrl+C)       yes
SIGTERM    15   polite stop request (default)    yes  ← prefer this
SIGKILL    9    kill immediately                 NO   ← last resort
SIGHUP     1    terminal closed / reload config  yes
SIGSTOP    19   suspend (Ctrl+Z sends SIGTSTP)   NO

See the full list: kill -l.

kill: send a signal

Despite the name "kill", this command actually sends a signal (SIGTERM by default):

kill 8           # send SIGTERM (15) to PID 8 — a polite stop request
kill -TERM 8     # equivalent, naming the signal explicitly
kill -9 8        # send SIGKILL — kill immediately, no chance to clean up
kill -HUP 8      # SIGHUP — many services read this as "reload config"

Try it:

sleep 300 &      # assume PID 8
kill 8           # stop it
ps -ef | grep "sleep 300" | grep -v grep   # (gone)

Why kill -9 differs from a plain kill — and when to use it

  • kill (SIGTERM) asks the process to stop itself. The process catches this signal, so it has time to save data, close connections, clean up, and exit cleanly. This is the way to use first.
  • kill -9 (SIGKILL) forces the kernel to kill the process immediately. The process cannot catch SIGKILL, so it has no time to clean up — it may leave behind unfinished data, lock files, hung connections.

The rule: try kill (TERM) first, give the process a chance to exit cleanly. Only use kill -9 when it refuses to stop after TERM. Many people reach for kill -9 right away — that's a bad habit, prone to corrupting data.

Kill by name instead of PID:

pkill -f "sleep 300"     # kill processes matching the command line
killall sleep            # kill every process named sleep

🧹 Cleanup

pkill -f "sleep" 2>/dev/null   # clean up any sleep processes left over from the exercises

Wrap-up

Everything running is a process, with a PID and PPID forming a tree from PID 1. View them with ps aux/ps -ef (snapshot) or top (dynamic); find them with pgrep. Run in the background with &, manage with jobs/fg/bg. Control them with signals: kill sends SIGTERM (polite stop — use first), kill -9 sends SIGKILL (forced kill, no cleanup — only when needed). SIGHUP is usually for reloading config.

You've now grasped the most core skill groups. Article 9 returns to everyday practicalities: compressing and decompressing files with tar/gzip — for backups and moving data.