Linux process management is a core sysadmin skill — whether you are hunting a runaway CPU hog, gracefully stopping a misbehaving daemon, or tuning scheduling priority for a batch job, knowing how to inspect and control processes keeps systems healthy. This guide covers the full toolkit: ps aux, top, htop, kill signals, nice/renice, background jobs, and the /proc filesystem, with practical examples you can use immediately.

Prerequisites

  • A Linux system (any distribution — Ubuntu, Debian, RHEL, Fedora, Arch)
  • Terminal access with a regular user account (some commands require sudo)
  • htop installed (apt install htop or dnf install htop) for the htop section
  • Basic familiarity with the command line

Listing Processes with ps

ps (process status) is the classic snapshot tool. It reads /proc and prints current process state at the moment you run it — unlike top, it does not refresh.

ps aux — BSD syntax

ps aux
ColumnMeaning
USEROwner of the process
PIDProcess ID
%CPUCPU usage since process started
%MEMResident memory as % of total RAM
VSZVirtual memory size (KB)
RSSResident Set Size — actual RAM used (KB)
STATProcess state (R=running, S=sleeping, Z=zombie, T=stopped)
COMMANDFull command line

Sort by CPU and show the worst offenders:

ps aux --sort=-%cpu | head -20
ps aux --sort=-%mem | head -20

Find processes by name without grep appearing in results:

ps aux | grep '[n]ginx'

ps -ef — UNIX syntax

ps -ef

ps -ef adds the PPID (parent PID) column, which is invaluable when tracing process trees. Use -eH or --forest for a tree view:

ps -eH
ps -ef --forest

Process states decoded

  • R — runnable (on CPU or in run queue)
  • S — interruptible sleep (waiting for I/O or an event)
  • D — uninterruptible sleep (usually disk I/O — cannot be killed)
  • Z — zombie (finished but parent has not reaped it)
  • T — stopped (Ctrl+Z or SIGSTOP)

A high count of D state processes points to I/O saturation. Z zombies are harmless in small numbers but indicate a parent not calling wait().

Interactive Monitoring with top

top gives a live, auto-refreshing view (default 3-second interval). Launch it, then use these keyboard shortcuts:

KeyAction
PSort by CPU usage
MSort by memory usage
TSort by cumulative CPU time
kPrompt for a PID to kill
rRenice a process
1Toggle per-CPU-core view
uFilter by username
fOpen field manager (add/remove columns)
qQuit
dChange refresh interval (seconds)
HShow individual threads instead of processes

The header summarizes load averages (1, 5, 15 minutes), CPU breakdown (us/sy/id/wa), and memory. A wa (I/O wait) above 10-15% usually means a storage bottleneck.

Run top non-interactively to capture a snapshot:

top -bn1 | head -30

Richer Process Monitoring with htop

htop is top with a colour UI, mouse support, and more intuitive controls. After installing and launching it, the function-key bar at the bottom guides you:

KeyAction
F2Setup (colours, columns, meters)
F3Search process list
F4Filter (show only matching processes)
F5Tree view (process hierarchy)
F6Sort column selector
F9Send signal to selected process
F10Quit
Arrow keysNavigate process list
SpaceTag a process for bulk action

htop shows CPU bars per core, memory and swap bars, and lets you scroll horizontally to see long command lines — all things top requires extra keystrokes to reveal.

Process Management Tools Comparison

Featurepstophtoppgrep/pkill
Live refreshNoYesYesNo
Mouse supportNoLimitedYesNo
Tree view--forest flagNoF5No
Send signalsNok keyF9Directly
Filter/searchPipe to grepu keyF4/F3By pattern/regex
Colour outputNoBasicRichNo
Script-friendlyExcellentPoorPoorExcellent
Install requiredBuilt-inBuilt-inYesBuilt-in

Use ps and pgrep/pkill in scripts; use top or htop interactively on servers.

Sending Signals: kill, pkill, killall

Signals are the primary IPC mechanism for process control. The most important ones:

SignalNumberDefault actionUse case
SIGTERM15Graceful terminateNormal stop — allows cleanup
SIGKILL9Immediate killProcess ignores SIGTERM
SIGHUP1Reload configTell daemons to re-read config
SIGSTOP19Pause (unblockable)Suspend a process
SIGCONT18ResumeResume a stopped process
SIGUSR1/210/12User-definedApp-specific (e.g., log rotation)

kill by PID

kill 1234          # SIGTERM — ask nicely
kill -15 1234      # explicit SIGTERM
kill -9 1234       # SIGKILL — no mercy
kill -HUP 1234     # reload config
kill -l            # list all signal names

Always try SIGTERM first. Give the process 10-30 seconds, then escalate to SIGKILL if needed.

pkill and pgrep — match by name or pattern

pgrep nginx                # list PIDs matching "nginx"
pgrep -u www-data nginx    # narrow to a specific user
pkill nginx                # SIGTERM all matching processes
pkill -9 nginx             # SIGKILL all matching
pkill -HUP nginx           # reload nginx config (same as kill -HUP $(pgrep nginx))

killall — kill all instances by exact name

killall firefox
killall -9 java
killall -u jcarlos          # kill all processes owned by a user

pkill accepts regex and partial matches; killall requires the exact process name. Prefer pkill in scripts.

Priority Tuning with nice and renice

Linux schedules processes using a niceness value from -20 (highest priority, least nice to others) to 19 (lowest priority). The default is 0. Only root can set negative values.

nice — set priority at launch

nice -n 19 tar -czf backup.tar.gz /var/data   # background backup, low priority
nice -n -5 ./realtime-processor                # higher priority (needs sudo)
sudo nice -n -10 ./critical-task

renice — adjust a running process

renice -n 10 -p 1234         # lower priority of PID 1234
sudo renice -n -5 -p 1234    # raise priority (root required)
renice -n 15 -u jcarlos      # lower priority for all of user's processes

Check current niceness with ps:

ps -o pid,ni,comm -p 1234

Background Jobs: bg, fg, and jobs

The shell’s job control lets you manage multiple tasks without opening extra terminals.

long-running-command &        # start directly in background
./script.sh                   # running in foreground
# press Ctrl+Z to suspend
[1]+  Stopped    ./script.sh

jobs                          # list jobs
# [1]+  Stopped    ./script.sh
# [2]-  Running    long-running-command &

bg %1                         # resume job 1 in background
fg %1                         # bring job 1 to foreground
fg %2                         # bring job 2 to foreground

disown %1                     # detach job from shell (survives logout)
nohup ./script.sh &           # immune to SIGHUP, output to nohup.out

& and bg still tie the process to the terminal session. Use nohup, screen, or tmux for jobs that must survive logout.

Exploring /proc

Everything ps and top know comes from the /proc virtual filesystem — a live window into the kernel’s process table.

ls /proc/1234/           # all files for PID 1234
cat /proc/1234/status    # human-readable status (Name, State, VmRSS, Threads…)
cat /proc/1234/cmdline   # full command line (null-separated)
cat /proc/1234/environ   # environment variables at launch
ls -l /proc/1234/fd/     # open file descriptors (sockets, pipes, files)
cat /proc/1234/maps      # memory map
cat /proc/self/status    # info about the current shell process

Useful system-wide /proc files:

cat /proc/loadavg        # 1m, 5m, 15m load + running/total processes
cat /proc/meminfo        # detailed memory statistics
cat /proc/cpuinfo        # per-core CPU details
cat /proc/uptime         # system uptime in seconds

Real-World Scenario: Production Server CPU Spike

You have a production web server that suddenly hits 100% CPU. Here is the playbook:

# 1. Identify the culprit
ps aux --sort=-%cpu | head -10

# 2. Get more detail (open files, network connections)
PID=<offending pid>
ls -l /proc/$PID/fd | wc -l     # file descriptor count
cat /proc/$PID/status            # check threads, memory
cat /proc/$PID/cmdline           # exact command

# 3. Try a graceful stop first
kill -15 $PID
sleep 15

# 4. Check if it stopped
ps -p $PID

# 5. Force kill if still running
kill -9 $PID

# 6. If it is a service, restart cleanly
sudo systemctl restart myapp

If the process is a known daemon, kill -HUP may be all you need to clear a stuck state without a full restart.

Gotchas and Edge Cases

SIGKILL cannot be caught or ignored. A process in uninterruptible sleep (state D, waiting on I/O) will not respond to SIGKILL until the I/O completes. In this case, the underlying device or NFS mount is usually the problem.

Zombie processes are not a leak. A zombie (state Z) holds a PID but no resources. It disappears when the parent calls wait(). If zombies accumulate, the parent process is buggy — killing the parent or fixing it is the solution, not killing the zombie directly.

ps %CPU is lifetime average, not current. The %CPU in ps aux is calculated over the process lifetime. A process that spiked yesterday and is now idle shows a low number. Use top or htop for real-time CPU.

nice requires root for negative values. Regular users can only increase niceness (lower priority). Mistyping nice -10 (which bash interprets as flag -1 0) is a common error — always use nice -n 10.

pkill matches substrings. pkill python will kill python3, python2, and any process with “python” in its name — including your editor if it embeds a Python interpreter. Use pgrep first to verify what will be matched.

Job control is per-shell. jobs only shows jobs started in the current shell session. Use ps aux | grep command to find detached processes.

Troubleshooting Common Issues

“Operation not permitted” when killing a process — you are trying to kill a process owned by another user or a root process. Use sudo kill PID.

Process immediately respawns after kill — a supervisor (systemd, supervisord, Docker) is restarting it. Stop the service with sudo systemctl stop service-name instead.

kill -9 does not work — the process is in D state (uninterruptible sleep). Check iostat -x 1 for I/O wait; the block device or network filesystem is stalled. A reboot may be necessary in extreme cases.

htop shows swap usage climbing — your system is memory-pressured. Use ps aux --sort=-%mem | head -10 to find the largest consumers and consider adding swap or restarting the offending application.

Load average high but CPU usage low — processes are waiting on I/O, not CPU. Check iostat, iotop, and D-state counts with ps aux | awk '$8 ~ /D/ {print}'.

Summary

  • ps aux gives a snapshot sorted by CPU or memory; use --forest for a tree view.
  • top and htop provide live monitoring; htop adds colour, mouse support, and F-key shortcuts.
  • Signals: always try SIGTERM (15) first, escalate to SIGKILL (9) only if necessary; SIGHUP (1) reloads most daemons.
  • pkill / pgrep are script-friendly alternatives to kill when you know a name rather than a PID.
  • nice / renice tune scheduling priority (-20 to 19); negative values require root.
  • bg / fg / jobs manage shell job control; use nohup or tmux to survive logout.
  • /proc/<PID>/ is the source of truth — status, cmdline, fd/, and maps reveal everything about a running process.