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.

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 auxThis 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 detailsx– 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 -efThe 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=-%cpuYou 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 auxIt 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 -efThis 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 --forestThe 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 nginxThis 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 grepOr use this cleaner approach with bracket notation:
ps aux | grep [n]ginxThe 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 -10The 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 1234The 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 -20This 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 1234If 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 ZThe 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 1234You 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 ^usernameThis 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,%cpuThis 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 -20Now 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 IDsuser,uid– Username or user ID%cpu,%mem– Resource percentagesvsz,rss– Memory sizesstat,state– Process statecomm,cmd– Command name or full command lineetime– Elapsed time since process startednice– 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.






