Skip to content

Inspecting Processes with ps

Process selection, custom output, state codes, and portability across Unix systems

owais
Aug 11, 20266 min read

ps, short for process status, reports a snapshot of selected processes. It can answer questions like who owns a PID, when it started, and which process launched it. The output does not update so tools like top, htop, or another monitor can watch changes over time.

Running ps without options usually shows processes owned by the current effective user and attached to the current terminal. The exact columns vary, but normally include the PID, terminal, accumulated CPU time, and command. Daemons and programs launched from another terminal may therefore be absent from plain ps output.

Three option styles

Linux's procps-ng implementation accepts three option styles:

StyleFormExamples
Unix/POSIXone dash-e, -f, -p 123, -o
BSDno dasha, x, u, aux
GNU-styletwo dashes--sort, --forest

On Linux, ps normally comes from procps-ng. Its manual calls the double-dash form “GNU-style”; ps itself is not part of GNU Coreutils. Mixing styles can change both the selected processes and the default columns. In scripts, explicit Unix-style selection and -o output are easier to reason about.

Common forms have different meanings:

  • ps -e or ps -A selects every process.
  • ps -ef selects every process and requests the Unix full format.
  • ps aux uses BSD options: a includes other users' terminal processes, x includes processes without a controlling terminal, and u selects a user-oriented format.
  • ps -aux should be avoided. On procps-ng it is formally a request involving the user named x, with a compatibility fallback when that user does not exist.

POSIX standardizes -A, -e, -a, -f, -l, several selectors, and -o. It does not standardize BSD's dashless bundles or procps-ng long options. BSD descendants also retain historical conflicts: FreeBSD documents that options such as -e, -f, -g, and -u do not all have their POSIX meanings.

Select processes and columns

Selection options choose processes. -o chooses and orders columns. Some implementations also support sorting.

ps -A                    # every process
ps -p 123,456            # these PIDs
ps -t pts/2              # processes attached to a terminal
ps -u alice              # effective user, on POSIX/procps-ng ps

On procps-ng, multiple positive selectors are additive. A process appears if it matches any of them. Supplying a selector also discards the narrow default selection. Thus, ps -p 123 -u alice selects PID 123 or Alice's processes.

-o produces a narrower, predictable listing:

ps -p 123 -o user,pid,ppid,pgid,stat,lstart,etime,time,args
ps -A -o user,pid,ppid,tty,etime,time,args

-o accepts a comma- or space-separated list. It may be repeated, and a field can be given a custom header with field=HEADER. An empty header suppresses that heading; if every heading is empty, ps omits the header row. That is handy when a script needs one value:

ps -p 123 -o ppid=

Programs that need reliable process metadata should use /proc, a system API, or a service manager. ps output can change with the operating system, locale, terminal width, selected personality, and version.

Reading the common fields

FieldMeaning
PIDProcess ID
PPIDParent process ID
PGIDProcess group ID, used for job control and group signaling
SIDSession ID
TTYControlling terminal; ? or - commonly means none
STATCurrent state plus optional modifiers
START/LSTARTStart time in a compact/full representation
ETIMEWall-clock time since the process started
TIMEAccumulated user plus system CPU time
%CPUImplementation-defined CPU-use calculation
%MEMResident memory as a percentage of physical memory on Linux
RSSResident set size, normally in KiB
VSZVirtual address-space size, normally in KiB
COMMExecutable or process name
ARGSCommand line, possibly modified, unavailable, or truncated

TIME and ETIME answer different questions. A process can have existed for a day (ETIME) while using only seconds of CPU (TIME) because it spent most of that day sleeping or waiting.

On Linux, %CPU is CPU time divided by the process's lifetime. BSD implementations may use a decaying recent average instead. Use a live monitor for current CPU load.

RSS estimates pages currently resident in physical memory. VSZ measures the virtual address space, which can include reserved but untouched mappings and shared libraries. RSS values also include shared pages in more than one process, so adding every process's RSS can overcount physical memory. These columns are useful for finding processes worth further inspection, but not for complete memory accounting.

A process can change the title that tools display. Arguments may also be unavailable or truncated. Put args last and request wide output during interactive investigation.

Process state

The first character of STAT is the main state. These codes are common on procps-ng:

CodeState
RRunning or runnable
SInterruptible sleep, waiting for an event
DUninterruptible sleep, usually waiting for I/O on Linux
TStopped by job control
tStopped while being traced
ZZombie: exited, but not yet reaped by its parent
IIdle kernel thread on Linux

Later characters are modifiers. On Linux, < and N indicate raised and reduced scheduling priority, s marks a session leader, l a multithreaded process, and + a member of the terminal's foreground process group. The vocabulary is not identical across systems; for example, FreeBSD also uses I for a process idle for more than about 20 seconds.

A zombie is no longer executing. Its parent has not collected its termination status with a wait operation, so the kernel keeps a small process-table record. Investigate the parent that failed to reap it.

Practical queries on Linux

procps-ng adds sorting, trees, and thread views:

# Highest lifetime CPU ratios first
ps -eo pid,ppid,user,stat,etime,%cpu,%mem,rss,args --sort=-%cpu

# Largest resident sets first
ps -eo pid,user,%mem,rss,vsz,args --sort=-rss

# Show parent-child relationships
ps -e -o pid,ppid,stat,etime,args --forest

# Show lightweight processes (threads)
ps -eLf

--sort accepts comma-separated keys, with - for descending and + for ascending. These long options and the exact thread flags are procps-ng features, so check man ps before using them on macOS or another BSD-derived system.

Use pgrep instead of ps ... | grep name for process discovery. The pattern can match the grep command itself, command lines are mutable, and the target can exit between being listed and acted upon. Any subsequent action still has a race unless the operating system provides a stable process handle.

The system continues running while ps constructs its listing. Processes can start, exit, change state, or change resource use between reads. Each row may already be stale by the time it is printed.


  1. procps-ng, ps(1) Linux manual page.
  2. IEEE and The Open Group, ps in the POSIX Programmer's Manual.
  3. The FreeBSD Project, ps(1) manual page.

Did you enjoy this article?

Recommend it — Standard Reader surfaces well-loved writing to more readers across the network.

Across the AtmosphereDiscussions