Viewing Processes¶
ps takes a snapshot of the process table, top refreshes it, and pgrep finds PIDs by name or attribute. Reading their columns correctly (state, CPU, resident memory, elapsed time) answers most "what is this server doing" questions.
Track: Core · Interview weight: High
Must-Know Facts¶
| Fact | Value | Verify with |
|---|---|---|
ps aux | BSD syntax: all processes, user-oriented columns, %CPU and %MEM | ps aux |
ps -ef | UNIX syntax: all processes with PPID and full command | ps -ef |
| Custom columns | -o pid,ppid,user,stat,%cpu,rss,etime,cmd; = after a name removes the header | ps -o pid= -p 1 |
| Sorting | --sort=-%cpu, --sort=-rss | ps -eo pid,rss,comm --sort=-rss |
| Select by name | -C nginx matches the command name exactly | ps -C nginx -o pid,args |
| Tree view | ps -ef --forest, pstree -p | pstree -p <pid> |
%CPU in ps | CPU time divided by lifetime, not current usage | top for current usage |
RSS vs VSZ | Resident memory in KiB vs virtual address space size | ps -o rss,vsz |
pgrep / pkill | Match the name (15 chars); -f matches the full command line; exit 1 when nothing matches | pgrep -a nginx |
pidof | PIDs of an exact program name, space-separated | pidof nginx |
top batch mode | top -b -n 1 prints one screen for scripts and tickets | top -b -n 1 |
top keys | P CPU, M memory, 1 per-CPU, H threads, c full command, k kill | inside top |
| Load average | Runnable plus uninterruptible (D) tasks, averaged over 1, 5 and 15 minutes | uptime |
watch | Reruns a command every 2 seconds (-n to change, -d to highlight changes) | watch -n 1 'ps -C nginx' |
ps aux and ps -ef¶
procps ps accepts BSD options (no dash), UNIX options (one dash) and GNU options (two dashes). The two common forms show the same processes with different columns.
ps aux | head -4
ps -ef | head -4
Output:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.5 0.1 22992 13992 ? Ss 18:54 0:01 /sbin/init
root 2 0.0 0.0 0 0 ? S 18:54 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 18:54 0:00 [rcu_gp]
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 18:54 ? 00:00:01 /sbin/init
root 2 0 0 18:54 ? 00:00:00 [kthreadd]
root 3 2 0 18:54 ? 00:00:00 [rcu_gp]
| Column | Meaning |
|---|---|
VSZ | Virtual memory size in KiB, including mapped but unused regions |
RSS | Resident set size in KiB: pages in RAM now, including shared libraries |
TTY | Controlling terminal; ? for daemons |
STAT | State plus flags, see Process States |
START / STIME | Start time |
TIME | Total CPU time consumed |
C | CPU utilization over the process lifetime, as an integer |
Custom Columns and Sorting¶
-o selects columns, and --sort orders by any of them; a leading - sorts descending. This form is the most useful in scripts and incident notes.
ps -eo pid,ppid,user,%cpu,%mem,rss,etime,comm --sort=-%cpu | head -5
ps -eo pid,user,rss,vsz,comm --sort=-rss | head -5
Output:
PID PPID USER %CPU %MEM RSS ELAPSED COMMAND
2113 2109 laborant 100 0.0 6960 00:02 stress-ng-cpu
2114 2112 laborant 100 3.7 309308 00:02 stress-ng-vm
2056 1 root 0.6 0.0 5812 00:03 systemd-hostnam
2040 1 laborant 0.5 0.1 11460 00:03 systemd
PID USER RSS VSZ COMMAND
2114 laborant 309308 373372 stress-ng-vm
843 root 165904 1381140 examiner
2110 laborant 39460 66164 stress-ng
2109 laborant 39408 66164 stress-ng
Time columns answer "when did this start" and "how much CPU has it used":
ps -o pid,lstart,etime,etimes,time,comm -p 1
Output:
PID STARTED ELAPSED ELAPSED TIME COMMAND
1 Wed Sep 16 18:54:51 2026 05:13 313 00:00:01 systemd
etimes gives elapsed seconds, which scripts can compare numerically.
Selecting Processes¶
ps -C nginx -o pid,ppid,user,args
ps -ef --forest | grep -A2 "[n]ginx: master"
Output:
PID PPID USER COMMAND
2102 1 root nginx: master process /usr/sbin/nginx
2103 2102 nginx nginx: worker process
2104 2102 nginx nginx: worker process
2105 2102 nginx nginx: worker process
2107 2102 nginx nginx: worker process
root 2102 1 0 19:00 ? 00:00:00 nginx: master process /usr/sbin/nginx
nginx 2103 2102 0 19:00 ? 00:00:00 \_ nginx: worker process
nginx 2104 2102 0 19:00 ? 00:00:00 \_ nginx: worker process
nginx rewrites its own argv, so args shows nginx: worker process instead of the binary path. The master runs as root to bind port 80; the workers run as nginx.
The bracket trick keeps grep out of its own results
grep nginx matches the grep nginx process too. The pattern [n]ginx still matches "nginx" but not the literal text "[n]ginx" in grep's own command line. pgrep avoids the problem entirely.
ps aux | grep nginx
Output:
root 2102 0.0 0.0 13988 1484 ? Ss 19:00 0:00 nginx: master process /usr/sbin/nginx
nginx 2103 0.0 0.0 14344 3536 ? S 19:00 0:00 nginx: worker process
nginx 2104 0.0 0.0 14344 3536 ? S 19:00 0:00 nginx: worker process
nginx 2105 0.0 0.0 14344 3536 ? S 19:00 0:00 nginx: worker process
nginx 2107 0.0 0.0 14344 3536 ? S 19:00 0:00 nginx: worker process
laborant 2141 0.0 0.0 3856 1892 ? S 19:00 0:00 grep nginx
pgrep, pidof and pstree¶
pgrep -a nginx; pgrep -u root -l nginx; pidof nginx
pgrep -c sshd; echo "rc=$?"
pstree -A -p $(pgrep -o nginx)
Output:
2102 nginx: master process /usr/sbin/nginx
2103 nginx: worker process
2104 nginx: worker process
2105 nginx: worker process
2107 nginx: worker process
2102 nginx
2107 2105 2104 2103 2102
0
rc=1
nginx(2102)-+-nginx(2103)
|-nginx(2104)
|-nginx(2105)
`-nginx(2107)
| Option | Effect |
|---|---|
-a | Print the full command line |
-l | Print the name |
-f | Match against the full command line |
-x | Exact name match |
-u user | Only this effective user |
-o / -n | Oldest / newest match only |
-P ppid | Only children of this parent |
-c | Count matches |
pgrep exits 1 when nothing matches, which makes it a process check in scripts: pgrep -x nginx >/dev/null || echo down. The count is 0 because this playground starts SSH through sshd.socket, so no sshd process exists until a client connects; a default RHEL install runs sshd.service instead.
top¶
top shows current usage, refreshed every 3 seconds. Batch mode prints a screen that can be pasted into a ticket.
top -b -n 1 -o %CPU | head -12
Output:
top - 19:00:05 up 5 min, 0 user, load average: 0.34, 0.09, 0.03
Tasks: 127 total, 3 running, 124 sleeping, 0 stopped, 0 zombie
%Cpu(s): 50.0 us, 2.4 sy, 0.0 ni, 47.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 8020.4 total, 7074.1 free, 851.3 used, 402.1 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 7169.1 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2113 laborant 20 0 66164 6960 4148 R 100.0 0.1 0:03.26 stress-+
2114 laborant 20 0 373372 309308 1004 R 100.0 3.8 0:03.25 stress-+
1 root 20 0 22992 13992 10068 S 0.0 0.2 0:01.64 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
Two processes each use a full CPU on a 4-CPU machine, which %Cpu(s) reports as 50% user time overall.
| Header field | Meaning |
|---|---|
load average | 1, 5 and 15-minute averages of runnable plus D-state tasks |
us / sy | User and kernel CPU time |
ni | User time of processes with positive nice values |
wa | Idle time while I/O was pending |
hi / si | Hardware and software interrupt time |
st | Time stolen by the hypervisor for other guests |
avail Mem | Memory available for new work without swapping, including reclaimable cache |
PR / NI | Kernel priority and nice value |
RES / SHR | Resident memory and the shared part of it |
TIME+ | CPU time in hundredths of a second |
Compare load average with the CPU count, not with 1
A load of 4 on this 4-CPU machine means full use; on one CPU it means 3 tasks waiting. Load also counts D-state tasks, so a high load with idle CPUs points to I/O or a hung mount, not to CPU demand. nproc gives the CPU count.
htop adds colors, a tree view (F5), per-thread display and mouse selection; it comes from EPEL on RHEL and from the main archive on Ubuntu.
Reading /proc Directly¶
ps and top read /proc/<pid>/stat and status. When ps is unavailable (a minimal container, or a fork limit), the same data is in the files:
cat /proc/$(pgrep -o nginx)/status | head -9
Output:
Name: nginx
Umask: 0000
State: S (sleeping)
Tgid: 2102
Ngid: 0
Pid: 2102
PPid: 1
TracerPid: 0
Uid: 0 0 0 0
A shell-only process list: for p in /proc/[0-9]*; do printf '%s %s\n' "${p#/proc/}" "$(< "$p/comm")"; done.
Common Errors¶
error: list of process IDs must follow -p¶
Cause: the command substitution after -p was empty, usually because pgrep matched nothing.
Fix: check the match first: pid=$(pgrep -x nginx) && ps -o pid,cmd -p "$pid".
Interview Checkpoints¶
L1: What is the difference between ps aux and ps -ef?
Say first: both list every process; aux is BSD style with %CPU, %MEM, VSZ and RSS, and -ef is UNIX style with PPID and start time.
Proof: ps aux | head -2; ps -ef | head -2
Follow-up: Which command gives exactly the columns you choose? (ps -eo.)
L1: What does load average measure?
Say first: the average number of tasks that are running, waiting for a CPU, or in uninterruptible sleep, over 1, 5 and 15 minutes.
Proof: uptime; compare with nproc.
Follow-up: How can load be high while the CPUs are idle?
L1: What is the difference between RSS and VSZ?
Say first: VSZ is the size of the virtual address space, and RSS is the part currently in physical memory, including shared libraries.
Proof: ps -o pid,vsz,rss,comm -p <pid>; a Java process often shows a VSZ many times its RSS.
Follow-up: Why does summing RSS over all processes overcount memory? (Shared pages; PSS in smaps_rollup divides them.)
L2: Show the five processes using the most memory.
Say first: sort by resident memory.
Proof: ps -eo pid,user,rss,comm --sort=-rss | head -6
Follow-up: How do you show the same for CPU right now instead of over the lifetime? (top -b -n 1 -o %CPU.)
L2: Print how long a process has been running, in seconds.
Say first: use the etimes column without a header.
Proof: ps -o etimes= -p $(pgrep -o nginx)
Follow-up: Where does ps get the start time? (Field 22 of /proc/<pid>/stat, in clock ticks since boot.)
L2: Write a check that restarts nothing but reports when nginx is not running.
Say first: use pgrep with an exact name and its exit status.
Proof: pgrep -x nginx >/dev/null || echo "nginx down"
Follow-up: Why is systemctl is-active nginx a better check on a systemd host?
L3: Users report slowness; top shows load average 12 on a 4-CPU server but CPU is 70% idle.
Say first: the load comes from tasks in uninterruptible sleep, so look for D-state processes and I/O wait.
Proof: ps -eo pid,stat,wchan:30,cmd | awk '$2 ~ /^D/', then vmstat 1 for b and wa, iostat -x 1 for device latency, findmnt -t nfs,nfs4 for hung mounts.
Follow-up: What does wchan tell you about where they are blocked?
L3: ps shows a process using 100% CPU, but top shows it at 0%.
Say first: ps reports average CPU over the process lifetime, and top reports usage in the last interval; the process was busy earlier.
Proof: ps -o pid,%cpu,time,etime -p <pid> against top -b -n 2 -d 2 -p <pid>
Follow-up: Which tool shows per-interval history? (pidstat 1 from sysstat.)
Related¶
- Process States: the
STATcolumn - Signals:
kill,pkillandkillall - Process Fundamentals:
/proc/<pid>files - Finding Files:
lsofand open files
Captured on Rocky Linux 10.2 (iximiuz Labs microVM, kernel 6.1.167), 2026-09.