Skip to main content

The Linux ps Command: Viewing and Understanding Processes

·1318 words·7 mins
Linux Learning Lab
Author
Linux Learning Lab
Writing about code, tools, and workflows.
Table of Contents

What ps Does
#

ps takes a snapshot of running processes at the moment you run it. Unlike top or htop which update continuously, ps gives you a static list you can filter, sort, and pipe into other commands.

The Two Syntax Styles
#

ps has a long history and accepts two different option styles. Both work — pick whichever you find more readable:

StyleExampleOrigin
UNIXps -efSystem V (options with dash)
BSDps auxBSD (options without dash)

They show similar information in slightly different formats. You’ll see both in documentation and scripts.

Common Options Explained
#

UNIX-style options (with dash)
#

OptionMeaning
-eSelect all processes (every process on the system)
-fFull format — shows UID, PID, PPID, start time, TTY, and full command
-u userSelect processes by username
-p pidSelect a specific process by PID
-o fmtCustom output format (you choose the columns)
--sortSort by a specified field
--forestShow process tree with ASCII art

-f is the most commonly paired option — without it, ps shows a minimal format (just PID, TTY, TIME, CMD). With -f, you get the full picture:

# Minimal output
ps -e
#   PID TTY          TIME CMD
#  1842 pts/0    00:00:00 bash

# Full format — much more useful
ps -ef
#  UID   PID  PPID  C STIME TTY      TIME CMD
#  mike  1842 1838  0 10:30 pts/0    00:00:00 bash

BSD-style options (no dash)
#

OptionMeaning
aShow processes from all users (not just yours)
uUser-oriented format (shows %CPU, %MEM, VSZ, RSS)
xInclude processes without a controlling terminal (daemons)
fShow process tree (forest)

These combine naturally — aux means “all users + user format + include daemons”:

# Without x — misses background services
ps au

# With x — shows everything including systemd, sshd, etc.
ps aux

Why ps -ef and ps aux show different things
#

ps -efps aux
Shows PPIDYesNo
Shows %CPU/%MEMNoYes
Shows VSZ/RSSNoYes
Full command pathYesYes

Use ps -ef when you care about process relationships (parent-child). Use ps aux when you care about resource usage.

Common Invocations
#

Show all processes (UNIX style)
#

ps -ef

Output:

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 Jun21 ?        00:00:03 /usr/lib/systemd/systemd
root         2     0  0 Jun21 ?        00:00:00 [kthreadd]
mike      1842  1838  0 10:30 pts/0    00:00:00 bash
mike      2105  1842  0 10:45 pts/0    00:00:02 vim server.c
ColumnMeaning
UIDUser who owns the process
PIDProcess ID
PPIDParent process ID
CCPU utilization
STIMEStart time
TTYTerminal (or ? for daemons)
TIMETotal CPU time consumed
CMDCommand that started the process

Show all processes (BSD style)
#

ps aux

Output:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1 169876 13280 ?        Ss   Jun21   0:03 /usr/lib/systemd/systemd
mike      1842  0.0  0.0   8556  5312 pts/0    Ss   10:30   0:00 bash
mike      2105  0.5  0.2  12456  9876 pts/0    S+   10:45   0:02 vim server.c
ColumnMeaning
USEROwner
PIDProcess ID
%CPUCPU usage percentage
%MEMMemory usage percentage
VSZVirtual memory size (KB)
RSSResident set size — actual RAM used (KB)
TTYTerminal
STATProcess state
STARTStart time
TIMETotal CPU time
COMMANDFull command

Just your processes
#

ps -f

Shows only processes owned by you in the current terminal.

Process tree
#

ps -ef --forest

Shows parent-child relationships with indentation:

root      1024     1  /usr/sbin/sshd
root      4521  1024   \_ sshd: mike [priv]
mike      4525  4521       \_ sshd: mike@pts/0
mike      4526  4525           \_ -bash
mike      4600  4526               \_ vim config.c

Or with the BSD-style equivalent:

ps auxf

Process States (STAT Column)
#

StateMeaning
RRunning or runnable
SSleeping (waiting for an event)
DUninterruptible sleep (usually disk I/O)
TStopped (suspended with Ctrl-z)
ZZombie (finished but parent hasn’t collected exit status)

Additional characters after the state:

ModifierMeaning
sSession leader
+Foreground process group
lMulti-threaded
<High priority
NLow priority (nice)

Example: Ss = sleeping session leader, R+ = running in foreground.

Filtering Processes
#

By name (with grep)
#

ps aux | grep nginx

Exclude the grep process itself:

ps aux | grep [n]ginx

The bracket trick makes the regex not match itself.

By user
#

# UNIX style
ps -u mike -f

# BSD style
ps aux | grep "^mike"

By PID
#

ps -p 1842 -f

By command name (without grep)
#

# Find PIDs by name
pgrep nginx

# With full details
pgrep -a nginx

# Count matching processes
pgrep -c nginx

Custom Output with -o
#

The -o flag lets you pick exactly which columns to display:

ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | head -10

Output:

  PID USER     %CPU %MEM COMMAND
 3421 mike     12.3  4.5 firefox
 2105 mike      0.5  0.2 vim
    1 root      0.0  0.1 systemd

Useful format specifiers
#

SpecifierMeaning
pidProcess ID
ppidParent PID
userUsername
uidUser ID
%cpuCPU percentage
%memMemory percentage
vszVirtual memory (KB)
rssResident memory (KB)
statProcess state
startStart time
timeCPU time consumed
commCommand name (short)
argsFull command with arguments
etimeElapsed time since start
niceNice value
ttyTerminal

Examples
#

# Show process name, PID, and elapsed time
ps -eo comm,pid,etime --sort=-etime | head -10

# Show memory hogs
ps -eo pid,user,rss,comm --sort=-rss | head -10

# Show all processes for a user with custom columns
ps -u mike -o pid,ppid,%cpu,%mem,etime,comm

Sorting
#

# Sort by CPU usage (descending)
ps aux --sort=-%cpu | head -10

# Sort by memory usage (descending)
ps aux --sort=-%mem | head -10

# Sort by start time (newest first)
ps aux --sort=-start_time | head -10

# Sort by PID
ps -ef --sort=pid

The - prefix means descending. Without it, ascending.

Combining with Other Tools
#

Find the top memory consumers
#

ps aux --sort=-%mem | head -10

Count processes per user
#

ps -eo user= | sort | uniq -c | sort -rn

Find long-running processes
#

ps -eo pid,etime,comm --sort=-etime | head -20

Watch a specific process over time
#

watch -n 1 'ps -p 2105 -o pid,%cpu,%mem,etime,comm'

Find zombie processes
#

ps aux | awk '$8 ~ /Z/'

Kill all processes matching a name
#

# Preview what will be killed
pgrep -a myapp

# Kill them
pkill myapp

Find which process is using a port
#

# First find the PID
ss -tlnp | grep :8080

# Then check what it is
ps -p <PID> -f

ps vs Other Tools
#

ToolBest for
psOne-time snapshot, scripting, custom output
topReal-time monitoring, interactive sorting
htopInteractive monitoring with better UI
pgrepFinding PIDs by name quickly
pidstatPer-process CPU/IO stats over time

Use ps when you need a scriptable, filterable list. Use top/htop when you’re watching things live.

Practical Scenarios
#

“What’s using all my CPU?”
#

ps aux --sort=-%cpu | head -5

“Is nginx running?”
#

pgrep -a nginx
# or
ps aux | grep [n]ginx

“What did PID 1 spawn?”
#

ps --ppid 1 -f

“How long has this process been running?”
#

ps -p 2105 -o etime=

“Show me everything about one process”
#

ps -p 2105 -f
# or for maximum detail
cat /proc/2105/status

Best Practices
#

  • Use ps aux or ps -ef as your default for seeing all processes — pick one style and stick with it
  • Use pgrep instead of ps | grep when you just need PIDs — it’s cleaner and doesn’t match itself
  • Use -o for custom output in scripts — it’s more reliable than parsing the default format with awk
  • Use --sort instead of piping to sort — it’s faster and handles column alignment correctly
  • Remember ps is a snapshot — if you need to catch a short-lived process, use top or trace tools instead
  • Check STAT for zombies (Z) and uninterruptible sleep (D) — these indicate problems worth investigating