ps is the Linux command that reports a snapshot of current processes. It reads process information from the /proc virtual filesystem and prints selected fields such as the process ID, parent process ID, owner, state, CPU and memory usage and the command line that started each process. In work with Linux processes, the ps command is the standard tool for answering the question of what is running right now.
Unlike interactive monitors such as top or htop, ps produces one static listing and exits. That makes it ideal for scripts, logs and pipelines, where its output can be filtered with grep, sorted and passed to other tools such as kill.
How the ps command gathers process information
The ps command does not query the kernel through a special interface. It walks the numbered directories in /proc, one per process, and reads files such as stat, status, cmdline and environ. Each value printed by ps corresponds to data the kernel exposes there.
Because the listing is assembled from many files, it is a point-in-time snapshot. Short-lived processes can start and finish between two runs, and a process may exit while ps is reading it. For continuous observation, top, htop or tracing tools are better suited.
On most distributions ps comes from the procps or procps-ng package. This implementation accepts three option styles, which is the main source of confusion for new users.
Option styles and essential invocations
The ps command supports UNIX, BSD and GNU option syntaxes at the same time. UNIX options take a dash, BSD options are written without one, and GNU long options use two dashes. The styles can be mixed, but ps -aux and ps aux do not mean exactly the same thing in strict mode.
| Style | Syntax | Example | Origin |
|---|---|---|---|
| UNIX (POSIX) | Single dash, groupable | ps -ef | System V tradition |
| BSD | No dash, groupable | ps aux | BSD tradition |
| GNU long | Two dashes | ps --forest | procps extensions |
A small set of invocations covers most daily administration. They differ in which processes are selected and which columns are shown.
| Command | Selects | Typical purpose |
|---|---|---|
ps | Processes of the current terminal | Quick check in a shell |
ps aux | All processes, user-oriented columns | General overview with CPU and memory |
ps -ef | All processes, full format | Parent IDs and start times |
ps -ef --forest | All processes as a tree | Viewing the process tree |
ps -u alice | Processes of one user | Auditing user activity |
ps -p 1234 -o pid,etime,cmd | One process, custom columns | Scripts and monitoring |
ps -eo pid,ppid,%mem,cmd --sort=-%mem | All, sorted by memory | Finding memory-heavy processes |
Reading the output columns
The columns printed by ps carry precise meanings that are often misread, especially those concerning CPU and memory.
| Field | Meaning | Notes |
|---|---|---|
| PID and PPID | Process and parent process ID | Basis of the process tree |
| STAT or S | Process state code | R, S, D, T, Z and modifiers |
| %CPU | CPU time divided by elapsed lifetime | Not the current instantaneous load |
| %MEM | Resident memory as share of RAM | Shared pages counted per process |
| VSZ | Virtual memory size in KiB | Includes mapped but unused memory |
| RSS | Resident set size in KiB | Physical memory currently used |
| NI and PRI | Nice value and priority | Related to process priority |
| TTY | Controlling terminal | A question mark means none |
The %CPU column is a lifetime average, so a process that was busy for one minute and then idle for an hour shows a low value. To see current consumption, top is more reliable. Similarly, summing RSS over many processes overstates total memory use, because shared libraries are counted in each process.
The state codes reveal what a process is doing: R means running or runnable, S interruptible sleep, D uninterruptible sleep, usually waiting for I/O, T stopped and Z a zombie process that has exited but not yet been reaped by its parent. Modifiers such as s for session leader, + for foreground process group and l for multithreaded add detail.
ps compared with related process tools
The ps command is one of several tools for inspecting processes. Choosing the right one depends on whether a snapshot, a live view or a targeted lookup is needed.
| Tool | Output type | Best for |
|---|---|---|
| ps | Static snapshot | Scripts, logs, precise columns |
| top | Live, refreshing view | Current CPU and memory load |
| htop | Interactive live view | Browsing and acting on processes |
| pgrep and pkill | Matching PIDs or signals | Finding or signaling by name |
| pstree | Tree view | Parent and child relationships |
Practical tips and common mistakes
Most problems with ps come from parsing its output carelessly in scripts. A few habits make results reliable.
- Use -o with explicit fields in scripts instead of parsing the default layout, which can change.
- Prefer pgrep over ps piped to grep, which otherwise matches its own grep process.
- Add ww for full command lines, because ps may truncate long commands to the terminal width.
- Use -L or -T to show threads, since the default listing shows one line per process.
- Kill the parent, not the zombie: a zombie cannot be killed; its parent must reap it or exit.
In containers, ps shows only processes within the current PID namespace, so the host and the container see different lists and different PIDs for the same process. Minimal container images sometimes lack ps altogether, in which case reading /proc directly gives the same information.
Put simply
Every program running on a Linux computer is a process. The ps command takes a quick photograph of all of them. It lists what is running, who started it and how much memory and processor time it uses.
It is like asking a receptionist for a list of everyone currently in a building. The list is accurate at that moment, but people come and go. To watch continuously, other tools such as top are more suitable.
In practice
A system administrator receives an alert that a web server is running low on memory. Logged in over SSH, she runs ps -eo pid,ppid,user,rss,etime,cmd --sort=-rss and sees that a reporting script started by cron 14 hours ago is holding almost 6 GB of resident memory.
The PPID column shows that the script was launched by a shell wrapper that never finished. She sends a TERM signal with kill to the wrapper, confirms with a second ps listing that both processes are gone, and adds a timeout to the cron job. Free memory returns to normal within seconds, and the web service keeps running without a restart.