Every running program on Linux is a process with a unique PID (process ID), an owner, and a share of CPU and memory. When an app hangs, a server slows down, or a port is mysteriously busy, process tools give you X-ray vision. This lesson covers listing processes with ps, monitoring live with top, and stopping them with kill.
When you run a command, the shell starts a child process. Each process has a PID, a parent (PPID), a user, and a state (running, sleeping, stopped, zombie). PID 1 is init/systemd, the ancestor of everything.
echo $$ # PID of your current shellps alone shows only processes in your current terminal—almost never what you want. The two spellings worth memorizing:
ps aux # every process, BSD style
ps -ef # every process, System V style (shows PPID)
ps aux | grep nginx # find a specific program
ps aux --sort=-%mem | head # top memory consumersKey ps aux columns: USER, PID, %CPU, %MEM, STAT (S sleeping, R running, Z zombie), and COMMAND. A neat trick: pgrep -a nginx finds PIDs by name without the grep-matching-itself problem.
top refreshes a ranked process table every few seconds:
topInside top: M sorts by memory, P by CPU, k prompts for a PID to kill, q quits. The header is as valuable as the list—load average (three numbers: 1, 5, 15-minute averages; roughly, values above your CPU core count mean saturation) and the memory line (remember that Linux uses "free" RAM for disk cache, so low "free" is normal; look at available).
If you can install it, htop shows the same data with colors, scrolling and mouse support: sudo apt install htop.
kill does not necessarily kill—it sends a signal:
kill 1234 # polite: SIGTERM to PID 1234
kill -9 1234 # forceful: SIGKILL
kill -HUP 1234 # ask a daemon to reload
pkill -f runaway.py # signal by matching the command line
killall node # signal every process named nodeAlways try plain kill first and give the process a few seconds—SIGKILL skips cleanup, which can leave lock files or corrupt data. Escalate to -9 only when a process ignores SIGTERM.
Your shell can juggle several tasks:
sleep 300 & # & starts a command in the background
jobs # list background jobs of this shell
fg %1 # bring job 1 to the foreground
# Ctrl+Z pauses the foreground process...
bg %1 # ...and bg resumes it in the backgroundCtrl+C sends SIGINT to interrupt the foreground process; Ctrl+Z suspends it. Background jobs die with your terminal unless you start them with nohup long_task.sh & or, better, inside tmux/screen on servers.
A classic incident: "address already in use". Find the culprit:
sudo ss -tulpn | grep :8080 # modern
sudo lsof -i :8080 # alternativeThen inspect it with ps -p <PID> -f before deciding to kill it.
sleep 500 &
jobs
ps aux | grep sleep
kill %1 # you can signal jobs by %number too
ps aux --sort=-%cpu | head -n 5ps aux snapshots them, top/htop monitor live.kill sends signals: SIGTERM (15) first, SIGKILL (9) as a last resort.pkill/killall target processes by name; pgrep -a finds PIDs cleanly.&, Ctrl+Z, jobs, fg, bg manage background work; ss -tulpn reveals port owners.Next lesson: Package Managers: apt and yum — install and update software the Linux way.