Process Management¶
Every running program on Linux is a process with a unique PID (process ID). This page covers how to view processes, find them, send them signals, change their priority, control background jobs, and read system load.
Tested on
AlmaLinux 9.4 and Ubuntu 22.04 LTS. The tools here are identical across distributions; htop may need installing (sudo dnf install htop after enabling EPEL, or sudo apt install htop).
Processes, PIDs, and the process tree¶
- Each process has a PID and a PPID (parent PID). Processes form a tree: a parent spawns children with
fork(). - PID 1 is the first process started by the kernel — on modern systems that's systemd. It is the ultimate ancestor of everything.
- When a parent dies before its child, the child is re-parented to PID 1.
- For managing long-running services, you usually want systemd rather than raw process tools — see systemd Service Management. The tools below are for ad-hoc inspection and control.
Viewing processes¶
ps — a snapshot¶
ps prints a one-time snapshot. Two classic flag styles:
# BSD style: every process, with CPU/memory and the controlling user
ps aux
# UNIX style: every process in full format with PPID
ps -ef
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 172412 13720 ? Ss 09:01 0:02 /usr/lib/systemd/systemd
root 742 0.0 0.0 82940 3204 ? Ss 09:01 0:00 /usr/sbin/sshd -D
nginx 1190 0.1 0.4 145320 17880 ? S 09:05 0:01 nginx: worker process
Key ps aux columns: PID, %CPU, %MEM, RSS (resident memory in KB), STAT (state: S=sleeping, R=running, Z=zombie, D=uninterruptible), and COMMAND.
# Filter to one program
ps aux | grep '[s]shd'
# Sort by memory or CPU usage (top consumers last)
ps aux --sort=-%mem | head
ps aux --sort=-%cpu | head
pstree — the hierarchy¶
top and htop — live view¶
In top: press M to sort by memory, P by CPU, k to kill a PID, 1 to show per-core CPU, q to quit.
htop is a friendlier, colorized alternative with mouse support, scrolling, and easy tree view (F5):
Finding processes¶
# Get the PID(s) of a named program
pidof sshd
pgrep sshd # also matches by pattern
# pgrep with more context
pgrep -a nginx # show full command line too
pgrep -u nginx # processes owned by user 'nginx'
pgrep -f 'python.*app.py' # match against the full command line
Signals and termination¶
You control processes by sending signals. kill despite its name just sends a signal — the default is SIGTERM.
# Politely ask a process to terminate (SIGTERM, signal 15)
kill 1190
kill -TERM 1190 # explicit, same thing
# Force kill — cannot be caught or ignored (SIGKILL, signal 9)
kill -9 1190
kill -KILL 1190
# Tell a process to reload its config (SIGHUP, signal 1)
kill -HUP 742
By name instead of PID:
# killall: match by exact process name
killall nginx
killall -9 nginx
# pkill: match by pattern (like pgrep)
pkill -f 'python.*app.py'
pkill -u baduser # kill all of a user's processes
Common signals¶
| Signal | Number | Default action | Use |
|---|---|---|---|
SIGHUP |
1 | Terminate | Hang-up; many daemons reload config on it |
SIGINT |
2 | Terminate | What Ctrl-C sends |
SIGQUIT |
3 | Terminate + core dump | Ctrl-\ |
SIGKILL |
9 | Terminate (uncatchable) | Last resort — process cannot clean up |
SIGTERM |
15 | Terminate | Default, graceful shutdown request |
SIGSTOP |
19 | Stop (uncatchable) | Pause a process |
SIGCONT |
18 | Continue | Resume a stopped process |
SIGTSTP |
20 | Stop | What Ctrl-Z sends |
SIGTERM before SIGKILL
Always try SIGTERM (kill PID) first. It lets the program flush buffers, close files, and exit cleanly. SIGKILL (-9) is brutal — the kernel destroys the process immediately, which can corrupt files or leave stale locks. Only escalate to -9 if SIGTERM is ignored.
Zombies
A process in state Z (zombie/defunct) has already exited; it's just an entry waiting for its parent to "reap" it. You cannot kill a zombie — it's already dead. If they pile up, the parent process is buggy; restart or kill the parent.
Priorities: nice and renice¶
The kernel scheduler uses a niceness value from -20 (highest priority, greediest) to +19 (lowest priority, most generous to others). Default is 0. Lower number = more CPU.
# Start a command with a higher niceness (lower priority)
nice -n 10 ./batch-job.sh
# Start with higher priority (negative needs root)
sudo nice -n -5 ./latency-sensitive
# Change the niceness of a running process
renice -n 5 -p 1190
# Renice all processes of a user
sudo renice -n 10 -u baduser
Tip
Only root can assign negative niceness (raise priority). Regular users can only be "nicer" (raise the number, lower priority). Check a process's niceness in the NI column of top or ps -o pid,ni,comm.
Job control¶
When you run a command in a terminal it runs in the foreground, tying up your shell. Job control lets you push work to the background.
# Start a command in the background with &
long-running-task &
# List jobs in the current shell
jobs
# Suspend the foreground process: press Ctrl-Z (sends SIGTSTP)
# Resume a stopped job in the background
bg %1
# Bring a job back to the foreground
fg %1
Surviving logout: nohup and disown¶
A background job still dies when you log out (it receives SIGHUP). To keep it running:
# nohup ignores SIGHUP and redirects output to nohup.out
nohup ./backup.sh &
# Or detach an already-running job from the shell
./backup.sh &
disown %1
Better: use systemd or tmux
For anything important, prefer a systemd service (see systemd Service Management) or a terminal multiplexer like tmux/screen. They survive disconnects far more reliably than nohup.
The /proc filesystem¶
/proc is a virtual filesystem exposing the kernel's view of every process and the system. Each PID has a directory /proc/<PID>/.
# What's the command line of PID 742?
cat /proc/742/cmdline | tr '\0' ' '; echo
# Environment, open files, current working directory of a process
sudo cat /proc/742/environ | tr '\0' '\n'
sudo ls -l /proc/742/fd
sudo ls -l /proc/742/cwd
# System-wide info
cat /proc/cpuinfo # CPU details
cat /proc/meminfo # memory details
cat /proc/loadavg # load averages + running/total processes
uptime # friendlier loadavg view
Quick system load views¶
A load average roughly equals the number of processes wanting CPU. Compare it to your core count: on a 4-core box, a load of 4.0 means fully busy; sustained above that means a backlog.
total used free shared buff/cache available
Mem: 15Gi 3.2Gi 8.1Gi 180Mi 4.1Gi 11Gi
Swap: 4.0Gi 0B 4.0Gi
Watch the available column, not free — Linux uses spare RAM for cache and reclaims it on demand.
Watch r (run queue), si/so (swap in/out — nonzero means memory pressure), and wa (CPU waiting on I/O).
Verify your work¶
# Start a background sleep, confirm it's running, then signal it
sleep 600 &
jobs
pgrep -a sleep
# Terminate it gracefully and confirm it's gone
kill %1
pgrep sleep || echo "no sleep processes — terminated cleanly"
# Confirm PID 1 is systemd
ps -p 1 -o pid,comm
You should see the sleep job appear in jobs/pgrep, then disappear after kill, and PID 1 reported as systemd.
Summary¶
- Every process has a PID and PPID; PID 1 is systemd, the root of the process tree.
- View processes with
ps aux/ps -ef, the tree withpstree, and live activity withtop/htop; find PIDs withpgrep/pidof. kill/killall/pkillsend signals; prefer SIGTERM (graceful) over SIGKILL (-9, uncatchable); SIGHUP often triggers a config reload.- Niceness (-20 to +19) sets scheduling priority via
nice/renice; only root can raise priority (negative values). - Job control (
&,jobs,fg,bg,Ctrl-Z) manages foreground/background work;nohup/disownsurvive logout, butsystemd/tmuxare more robust. /proc/<PID>/exposes per-process kernel state;uptime,free -h, andvmstatgive quick system-load snapshots.