How to Use ps Command in Linux: The Process Tool Every Admin Needs

Robert Johnson

If you’ve spent any time managing Linux systems, you’ve probably typed ps aux | grep something more times than you can count. The ps command is one of those tools that’s so fundamental, you use it without thinking. But here’s the thing – most people only scratch the surface of what ps can do.

I’ve been troubleshooting processes on Linux servers for over a decade, and I still discover new ways to use ps. Whether you’re hunting down a runaway process eating all your CPU at 3 AM or trying to understand why your application won’t die gracefully, ps is the tool you reach for first.

Let me show you how to actually use the ps command effectively, not just copy-paste the same commands from Stack Overflow.

What is the ps Command and Why You Need It

The ps command shows you a snapshot of currently running processes on your system. Think of it like taking a photograph – it captures what’s happening at that exact moment, then stops. This is different from the top command for real-time monitoring, which continuously updates like a video feed.

Why does this matter? Because sometimes you don’t need real-time updates. You need to capture process information, log it, or script against it. That’s where ps shines.

RackNerd Mobile Leaderboard Banner

Reading Process Information from /proc

Here’s something most tutorials don’t tell you: ps doesn’t have some magical ability to see running processes. It reads them from the /proc filesystem – a special pseudo-filesystem that the kernel maintains in memory.

Every running process gets a directory under /proc named after its PID. When you run ps, it’s essentially reading those directories and formatting the data for you. You can see this yourself:

ls /proc/
cat /proc/1/status

The first command lists all process directories. The second shows detailed status information for process ID 1 (usually systemd or init). Understanding this helps you appreciate what ps is actually doing under the hood. If you want the deep dive, check out the /proc filesystem documentation.

ps vs top: When to Use Which

I get asked this all the time. Here’s my rule of thumb:

  • Use ps when: You need to capture data for scripts, logs, or automation
  • Use ps when: You want to grep, awk, or pipe output to other commands
  • Use ps when: You need to see parent-child process relationships
  • Use top when: You want to watch processes change over time
  • Use top when: You need interactive sorting and filtering

I probably use ps ten times more often than top because most of my troubleshooting involves finding a specific process, getting its PID, and then doing something with that information. That workflow is perfect for ps.

Understanding ps Command Syntax: BSD vs Unix Styles

Okay, this is where ps gets weird. The ps command supports three different syntax styles, and they can’t be mixed. This confuses everyone at first, including me when I started.

Why? Historical baggage. Linux inherited ps implementations from both BSD Unix and System V Unix, and the maintainers decided to support both syntaxes. Then they added GNU long options for good measure.

BSD Style Options (No Dash)

BSD-style options don’t use a leading dash. The most common example:

ps aux

This shows all processes with user-oriented output. The letters mean:

  • a – Show processes from all users (not just yours)
  • u – Display user-oriented format with extra details
  • x – Include processes without a controlling terminal

The output includes columns like USER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT, START, TIME, and COMMAND. This is my go-to format for monitoring memory usage and general troubleshooting.

Unix System V Style (With Dash)

System V options use a leading dash. The equivalent command to ps aux is:

ps -ef

The flags mean:

  • -e – Select all processes
  • -f – Full format listing

This gives you different columns: UID, PID, PPID, C, STIME, TTY, TIME, and CMD. Notice it shows PPID (parent process ID) by default – super useful when you’re investigating process hierarchies.

GNU Long Options

GNU-style options use double dashes and full words:

ps --forest
ps --sort=-%cpu

You can mix GNU long options with either BSD or Unix styles, but you can’t mix BSD and Unix together. The ps man page has the complete reference, though I’ll warn you it’s dense.

Essential ps Commands You’ll Actually Use

Let me cut through the noise and show you the commands I actually use in production. These cover 90% of real-world scenarios.

ps aux: The Go-To Command

This is the command I type most often:

ps aux

It shows every process with detailed resource usage. When a server is running slow, this is usually my first command. I scan the %CPU and %MEM columns to spot obvious problems.

The output looks like this:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1 168436 11944 ?        Ss   Jan15   0:42 /sbin/init
alex      1234  5.2  2.1 456780 87332 ?        Sl   08:30   2:15 /usr/bin/python3 app.py

Quick breakdown of what matters:

  • PID – Process ID, needed for killing processes
  • %CPU – Percentage of CPU time used
  • %MEM – Percentage of physical memory used
  • VSZ – Virtual memory size in KB
  • RSS – Resident set size (actual physical memory in KB)
  • STAT – Process state (more on this soon)

ps -ef: Full Process Listings

When I need to see parent-child relationships, I switch to:

ps -ef

This format shows the PPID column, which tells you which process started each process. This is incredibly useful when tracking down orphaned processes or understanding how your application spawns workers.

I also use this with --forest to visualize the process tree:

ps -ef --forest

The forest view indents child processes under their parents. Beautiful for understanding systemd service hierarchies or complex application architectures.

Filtering with grep

Here’s the workflow you’ll use constantly:

ps aux | grep nginx

This finds all nginx processes. I’ve probably typed variations of this command thousands of times. The grep command filters the ps output to show only lines containing “nginx”.

Pro tip: grep itself will show up in the results (because “grep nginx” contains “nginx”). You can filter it out:

ps aux | grep nginx | grep -v grep

Or use this cleaner approach with bracket notation:

ps aux | grep [n]ginx

The brackets make grep search for “nginx” but its own command line shows “[n]ginx” so it won’t match itself. Clever, right?

Sorting by CPU and Memory Usage

Want to find the resource hogs? Sort the output:

# Top CPU consumers
ps aux --sort=-%cpu | head -10

# Top memory consumers
ps aux --sort=-%mem | head -10

The minus sign sorts in descending order. Pipe to head to see just the top 10. This is my go-to command when investigating checking CPU usage issues on production servers.

Understanding ps Output Columns

Let’s dig into what those columns actually mean, because understanding the output is how you move from “running commands” to “solving problems.”

Process States (STAT Column)

The STAT column shows the process state using letter codes. Here are the important ones:

  • R – Running or runnable (actively using CPU or waiting for CPU)
  • S – Sleeping (waiting for an event to complete)
  • D – Uninterruptible sleep (usually waiting for I/O, can’t be killed)
  • Z – Zombie (terminated but not reaped by parent)
  • T – Stopped (paused, usually by a signal)
  • I – Idle kernel thread

You’ll often see additional characters:

  • < – High priority process
  • N – Low priority (nice)
  • L – Has pages locked in memory
  • s – Session leader
  • l – Multi-threaded
  • + – In foreground process group

So Ssl means: Sleeping, session leader, multi-threaded. That’s typical for a daemon like nginx or apache.

CPU and Memory Metrics

Understanding these metrics helps you spot problems:

%CPU shows the percentage of CPU time used since the process started. This isn’t a real-time snapshot – it’s averaged over the process lifetime. A process showing 100% might have been idle for hours and just started hammering the CPU.

%MEM is the percentage of physical RAM the process is using right now. This is based on RSS, not VSZ.

VSZ (Virtual Size) is all the memory the process has allocated, including shared libraries and swapped-out pages. This number is often huge and misleading.

RSS (Resident Set Size) is the actual physical memory the process is using. This is what you care about when investigating memory issues. Multiple processes can share libraries, so RSS across all processes might add up to more than your total RAM.

Process IDs and Parent PIDs

Every process has a unique PID (process ID). When you need to kill a process, you use its PID:

kill 1234

The PPID (parent process ID) tells you which process created this one. Process 1 (init or systemd) is the ancestor of all processes. When a parent dies, its children get reparented to process 1.

This matters when debugging. If you see a bunch of zombie processes all with the same PPID, that parent process has a bug – it’s not properly reaping its dead children.

Real-World ps Use Cases for System Admins

Theory is great, but let me show you how I actually use ps when something breaks.

Finding Which Process is Using Resources

Server load is high. What’s the culprit?

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

This shows the top 20 CPU consumers. Usually one or two processes jump out immediately. Then I investigate further:

ps -fp 1234  # Get full details on PID 1234

If it’s a legitimate process misbehaving, I might check what files it has open using the lsof command to understand what it’s doing.

Identifying Zombie Processes

Zombie processes are dead but haven’t been reaped. They don’t use CPU or memory, but they do consume PIDs. If you have enough zombies, you can run out of PIDs.

ps aux | grep Z
ps aux | awk '$8 ~ /^Z/ { print }'

The first command works but shows grep too. The second is cleaner – it uses awk to filter for processes with STAT starting with Z.

Once you find zombies, look at their PPID:

ps -ef | grep Z

The parent process is buggy and not calling wait(). Your options are to fix the parent process code or restart it.

Getting PIDs for kill Commands

This is probably the most common workflow:

# Find the process
ps aux | grep application_name

# Kill it
kill 1234

# If it won't die
kill -9 1234

You can also use pgrep as a shortcut, but I tend to use ps because I want to verify I’m killing the right thing before I actually kill it.

Monitoring Specific User Processes

Want to see what a specific user is running?

ps -u username
ps aux | grep ^username

This is useful for security audits or when users report issues. I’ve used this countless times when someone says “my job won’t start” and I need to see if they already have 20 copies running.

Custom ps Output: Formatting with -o

Here’s where ps gets really powerful for scripting and automation.

Selecting Specific Columns

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

ps -eo pid,ppid,cmd,%mem,%cpu

This shows only PID, PPID, command, memory percentage, and CPU percentage. Clean output that’s easy to parse in scripts.

You can combine this with sorting:

ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head -20

Now you have a custom view of the top 20 CPU consumers with just the data you care about.

Creating Custom Views

I have several custom ps commands saved in my .bashrc as aliases:

alias psmem='ps -eo pid,ppid,cmd,%mem --sort=-%mem | head -20'
alias pscpu='ps -eo pid,ppid,cmd,%cpu --sort=-%cpu | head -20'
alias psme='ps -u $USER -o pid,ppid,cmd,%mem,%cpu'

These give me quick access to common views without typing long commands.

For monitoring, combine ps with watch:

watch -n 2 'ps -eo pid,ppid,cmd,%cpu --sort=-%cpu | head -10'

This runs the command every 2 seconds, giving you a constantly updating view of top CPU consumers. It’s like a custom, minimal version of top focused on exactly what you need.

Available format specifiers include:

  • pid, ppid – Process and parent IDs
  • user, uid – Username or user ID
  • %cpu, %mem – Resource percentages
  • vsz, rss – Memory sizes
  • stat, state – Process state
  • comm, cmd – Command name or full command line
  • etime – Elapsed time since process started
  • nice – Nice value (priority)

Check the proc(5) documentation for the complete list.

Common ps Command Mistakes to Avoid

Let me save you from some headaches I’ve caused myself over the years.

Don’t type ps -aux when you mean ps aux. In POSIX mode, -a and -u are separate flags, and x becomes a username. So ps -aux tries to show processes owned by user “x”. You’ll get a warning but weird results. No dash for BSD style.

Remember ps is a snapshot, not real-time. If you run ps aux twice, you might see different results. The process could have exited or changed state. Don’t assume process 1234 is still running just because it was there 30 seconds ago when you checked.

Watch out for truncated command output. By default, ps truncates the COMMAND column to fit your terminal width. Use ps auxww (BSD) or ps -efww (Unix) to show full command lines without truncation. I can’t tell you how many times I’ve been confused by truncated Java classpath commands.

Process state isn’t the same as CPU usage. A process in “R” (running) state might be using 0% CPU if it just woke up and is waiting for a CPU time slice. And a process in “S” (sleeping) state doesn’t mean it’s idle – it might be sleeping for microseconds between CPU bursts.

Don’t ignore the column headers. The BSD and Unix output formats use different column names and values. STAT and S both show process state, but the format differs slightly. CMD and COMMAND aren’t exactly the same. Read the headers.

Be careful with zombie process counts. I’ve seen people panic about 50 zombie processes. Zombies don’t consume resources – they’re already dead. They’re a symptom of a buggy parent process, not a resource crisis. The real problem is the parent needs fixing.

Putting It All Together

The ps command is one of those tools that seems simple on the surface but has incredible depth. I’ve been using it professionally for years and still discover new tricks.

Start with ps aux for general troubleshooting. Use ps -ef --forest when you need to understand process relationships. Build custom views with -o when you’re scripting or need specific data. And always remember – ps shows you a moment in time, not a continuous stream.

The next time you’re troubleshooting a performance issue, tracking down a misbehaving daemon, or just trying to understand what your system is actually doing, you’ll reach for ps. And now you’ll know how to use it effectively instead of just copying commands from Stack Overflow.

Want to level up your Linux process management skills? Check out how to combine ps with powerful tools for complete system visibility. The real power comes from chaining commands together – that’s where the Unix philosophy really shines.