Why ps
When you need a one-shot process list for a script, a pipe, or logs, ps is
the right tool. For interactive use, see [[cmd-htop|htop]]. For a single process,
use top -p PID or cat /proc/PID/status.
ps reads /proc/*/stat, cmdline, and status, the same sources htop uses, but
captures a single frame.
Two dialects and why it hurts
Historically:
- BSD style:
ps aux(NO dash), short single-letter options - UNIX style:
ps -ef(WITH dash), System V
Modern procps-ng (Linux) accepts both, plus ps --GNU (double dash). Mixing
options from different styles in one call is a source of bugs:
ps -aux ← UNIX -a + parsed as BSD `aux`. Often works, but not
guaranteed (different ps builds interpret this differently).
The rule: use either ps aux or ps -ef.
ps aux: what it shows
$ ps aux | head -3
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 168740 11252 ? Ss Apr01 0:23 /sbin/init
root 2 0.0 0.0 0 0 ? S Apr01 0:00 [kthreadd]
Columns:
| Column | Meaning |
|---|---|
| USER | owner |
| PID | process id |
| %CPU | average since start (not realtime!) |
| %MEM | RSS / total RAM |
| VSZ | virtual size in KiB (includes mmap regions and non-resident pages) |
| RSS | resident set size in KiB, what is actually in RAM |
| TTY | controlling terminal; ? means none (daemon) |
| STAT | state; see below |
| START | when started |
| TIME | total CPU time |
| COMMAND | argv |
STAT flags
R: running or runnableS: interruptible sleep (normal for most processes)D: uninterruptible sleep (usually I/O; cannot be killed even with SIGKILL)T: stopped (Ctrl-Z, SIGSTOP)Z: zombie (exited, but parent has not reaped it)I: kernel idle thread (procps-ng 3.3+)
Additional flags:
s: session leaderl: multi-threaded+: foreground in its process group<: high priority (nice < 0)N: low priority (nice > 0)L: has locked pages
Example: Ssl+ means session leader, sleeping, multi-threaded, foreground.
ps -ef: a slightly different set
$ ps -ef | head -3
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Apr01 ? 00:00:23 /sbin/init
root 2 0 0 Apr01 ? 00:00:00 [kthreadd]
- PPID: parent PID (absent in
ps auxwithoutf) - C: CPU utilization
- STIME: start time
- CMD: equivalent of COMMAND
When you need PPID, ps -ef is shorter than ps -eo pid,ppid,....
-o: custom format
The most flexible mode. List columns separated by commas:
ps -eo pid,ppid,user,nice,pri,rss,vsz,stat,wchan,cmd
Commonly used fields:
| Field | Meaning |
|---|---|
pid, ppid, pgid, sid | ids |
user, uid, group, gid | owners |
nice (ni), pri | priority |
rss, vsz, pmem | memory |
pcpu, time, etime | CPU and time |
stat, state | state |
wchan | kernel location where the process is sleeping |
comm, cmd, args | name/argv |
cgroup | cgroup path (systemd unit name, container) |
lstart | absolute start timestamp |
tty, class, policy | miscellaneous |
Rename a column header with =: ps -eo pid,user,rss=Memory_KB,cmd.
Sorting: --sort=-%cpu (minus means descending):
ps -eo pid,user,pcpu,pmem,cmd --sort=-pcpu | head
Thread view
By default ps shows only processes. To see threads:
ps -eLf # all threads (-L) with extended form (-f)
ps -T -p $PID # threads of a specific process
ps -o pid,tid,nlwp,cmd $PID
- PID: process id (TGID in the kernel)
- LWP / TID: thread id (PID in the kernel)
- NLWP: number of threads in the process
Tree mode
ps -ef --forest # ASCII tree
ps auxf
pstree -p # separate utility, cleaner output
pstree -psaT 1 # tree with PIDs and cmdline
Common use cases
# Top 10 by CPU
ps -eo pid,user,pcpu,cmd --sort=-pcpu | head -11
# Top 10 by memory
ps -eo pid,user,rss,cmd --sort=-rss | head -11
# All processes of a user
ps -fu www-data
# How long a process has been running
ps -o pid,etime,cmd -p $PID
# All zombies
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /^Z/'
# PIDs of nginx (for xargs)
pgrep nginx # alternative to ps + grep
pidof nginx
For scripting, pgrep/pidof is cheaper and clearer than ps | grep.
When something looks wrong
ps aux | grep fooshows grep itself. Usepgrep fooorpgrep -f(matches against cmdline). Or useps aux | grep '[f]oo'.- %CPU over 100. That is the sum across all CPUs for a multi-threaded process.
Use
ps -eLfor per-thread values. - VSZ is enormous (TB), RSS is small. Normal: VSZ includes mmap regions that are not resident. Look at RSS instead.
- No argv visible (
[kworker/...]). Kernel thread, no userspace argv. Brackets mean kernel thread. - Script truncates COMMAND. The terminal is narrow.
ps -e -ww -o cmddisables truncation. psin a pipe sees its own PID. Standard behavior. Ignore it or filter it out.
Alternatives
pgrep/pkill: search or kill by name or cmdline patternpidof: PID by exact binary name/proc/$PID/status: read data for one process directlytop/[[cmd-htop|htop]] - interactive