ps Command Explained - Track, debug, and manage Linux processes

Last updated: August 18th 2025

Introduction

Your server's running a bunch of stuff right now. Web processes, database connections, system services, maybe some cron jobs you forgot about. Usually, you don't think about it much until something breaks or your server starts crawling.

That's when you would reach for ps (arguably short for process snapshot or process status). It's probably the most boring-sounding command in Linux, but it saves your skin when things go sideways. Need to see if MySQL actually restarted? Check what's hogging your CPU? Find out why your PHP processes keep multiplying. ps has the answers.

The problem is that ps has several different options, and most tutorials only show the basics (which aren't helpful).

So, let's take a deep dive and focus on the PS commands that actually matter for running web servers and applications. I will start with the basics and then guide you through checking what processes are running and interpreting that information.

From there, I will move on to more advanced commands to help you quickly identify and resolve issues, ensuring your systems run smoothly.

Have a look!

ps Fundamentals

You launch your terminal and type ps. A measly three lines appear, showing bash, ps, and one other process.

That's because ps, without any flags, only shows processes tied to your current terminal session.

ps works by reading the /proc filesystem. Linux creates a directory for every process under /proc, numbered by process ID. Want to see this yourself? Run:

$ ls /proc | head -20

And you'll spot numbered directories mixed in with files like cpuinfo and meminfo. Each numbered directory contains everything Linux knows about that process.

When you run ps, the command opens these directories, reads the status files, and formats the information.

The power of ps lies in its snapshot approach. Unlike top which refreshes every few seconds, ps captures one moment in time. This matters when you're tracking down issues.

You can run ps aux > processes_before.txt, make changes to your system, then run ps aux > processes_after.txt and compare the files. Try doing that with the top.

Process states matter more than most people realize. Every process sits in one of several states: running, sleeping, stopped, or zombie.

PS shows these states in the STAT column using single letters. A process marked 'Z' is finished but its parent hasn't cleaned up yet: a classic zombie process. You'll see 'S' for sleeping (waiting for input), 'R' for running, and 'T' for stopped.

Basic ps Syntax

ps inherited a messy syntax situation from Unix history. Three different Unix variants contributed their own option styles, and modern ps supports all of them. This creates confusion but also flexibility.

BSD Style (no dashes):

ps aux

ps axf

ps alx

UNIX Style (single dashes):

ps -ef

ps -aux

ps -l

GNU Style (double dashes):

ps --help

ps --forest

ps --sort=cpu

The letters in the ps aux each contain different information:

a tells ps to show processes from all users, not just the ones you own. Without this, you'd only see your bash session and anything you started. With it, you see nginx, mysql, php-fpm - all the server processes that matter.

u switch to a user-oriented output format. Instead of showing just process IDs and names, you get usernames, CPU percentages, memory usage, and start times. This format includes the most useful columns for day-to-day server management.

x includes processes without a controlling terminal. Web servers, databases, and system daemons run in the background without terminals attached. Skip this flag, and you'll miss most of the critical stuff running on your server.

Here's what each column means in ps aux output:

  • USER shows which account owns the process. On Ubuntu servers, you'll typically see root for system services, www-data for Apache/nginx processes, mysql for database processes. This helps you understand what's running with which privileges.
  • PID gives you the process ID (the unique number Linux assigns when the process starts). You'll use this number with kill, strace, and other debugging tools.
  • %CPU shows CPU usage as a percentage. This number represents average CPU usage since the process started, not current usage. A process showing 50% CPU might be idle, but was busy earlier.
  • %MEM displays memory usage as a percentage of total system RAM. It is more useful than absolute memory numbers because it shows the impact on your server.
  • VSZ stands for Virtual Set Size, which measures how much virtual memory the process has allocated. This includes memory that might not actually be used yet. PHP processes often show high VSZ numbers.
  • RSS stands for Resident Set Size, i.e., how much physical RAM the process currently uses. This number matters more than VSZ for understanding actual memory consumption.
  • TTY shows which terminal the process is attached to. Background services show '?' because they don't have terminals. You might see pts/0 or pts/1 for processes you started from SSH sessions.
  • STAT displays the process state using letter codes. 'S' means sleeping, 'R' means running, 'D' means uninterruptible sleep (usually waiting for disk I/O). Additional letters provide more detail: 's' means session leader, '+' means in foreground process group.
  • START tells you when the process began. For processes that started today, you see the time, and for older processes, you see the date.
  • TIME shows total CPU time used by the process since it started. This accumulates over the process lifetime, so a web server that's been running for weeks might show hours of CPU time.
  • COMMAND displays the actual command line that started the process, including arguments and flags. This column often gets truncated, but you can see the full command using ps auxww.

Before going further, I'll use Ubuntu examples throughout this guide. Ubuntu dominates web server deployments, and if you're running a Webdock VPS, you may have picked Ubuntu, too. The commands work the same on other Linux distributions, but package and default process names might vary slightly.

ps vs Other Process Tools

Your server runs different tools for checking processes, and each one works better for specific situations. When you need a quick snapshot of what's running, ps beats the alternatives.

Other tools like top and htop keep refreshing their displays. That's great when you want to watch processes change over time, but terrible when you need to capture a specific moment. ps gives you one clean snapshot that you can save to a file, email to a colleague, or compare with another snapshot later. Try saving top output to a file and you'll get a mess of control characters and formatting codes.

Every Linux server ships with ps installed. You won't find htop or other fancy monitoring tools on many production servers, especially minimal installations that prioritize security and simplicity.

systemctl shows you what the service manager thinks is happening, while ps shows you what's actually running on the system. Sometimes, these don't match, especially after crashes or when someone manually kills processes. The process table doesn't lie.

Scripts need predictable output that doesn't change format or expect user input. ps gives you the same columns in the same order every time. You can write a monitoring script that parses ps output and trust it'll work months later. htop expects someone to press keys and navigate around.

You want to find specific processes quickly without scrolling through screens of information. ps aux | grep nginx gets you nginx processes immediately. Opening htop, waiting for it to load, then searching takes longer and gives you less control over the output format.

ps plays nicely with other command-line tools. You can sort it, filter it, or extract specific columns easily.

When to Choose Alternatives Over ps

ps isn't always the right tool. Sometimes other commands work better for what you're trying to accomplish.

top makes more sense when processes keep changing. Your web server's under heavy load and you want to watch how different processes compete for CPU and memory over time. ps shows you one frozen moment, but top lets you see the patterns. You can spot processes that spike periodically or gradually consume more resources.

htop beats ps for interactive troubleshooting. You need to kill several related processes or want to sort by different columns on the fly. htop lets you mark processes with the spacebar, kill them with F9, or change the sort order without retyping commands. ps requires you to note process IDs, switch to another command, then come back.

systemctl works better for managing services. You want to restart nginx, check if it's set to start automatically, or see recent log entries. systemctl handles the service lifecycle properly, while ps just shows you what's currently running. Killing processes with ps doesn't clean up properly like stopping services does.

pgrep and pkill save time for simple tasks. You need all the process IDs for PHP-FPM workers or want to kill every stuck MySQL connection. pgrep php-fpm gives you just the numbers, while ps aux | grep php-fpm includes extra information you don't need.

iostat and vmstat show system performance better than ps when your server feels slow but you can't pinpoint why.

Combining ps with Other Commands

PS dumps a lot of information on your screen, and that's usually not what you want.

You'll probably use grep more than anything else. ps aux | grep nginx cuts through all the noise and shows you just the nginx processes. The same deal applies to ps aux | grep www-data if you want to see what your web server user is doing. grep digs through process names, usernames, and whatever's on the command line.

Want to see which processes are eating your CPU? ps aux --sort=-%cpu puts the hungry ones at the top. For memory hogs, try ps aux --sort=-%mem. Take out the minus sign, and you get the opposite order.

Your server might run hundreds of processes. You don't need to see them all. ps aux | head -20 gives you the first twenty lines. ps aux | tail -10 shows the last ten, usually the stuff that started recently.

awk picks out specific columns when you don't need everything. ps aux | awk '{print $2, $11}' hands you the process IDs and command names. ps aux | awk '$4 > 10' shows processes using more than 10% memory.

You can string commands together. ps aux | grep php | sort -k4 -nr finds PHP processes and sorts them by memory usage, heaviest first. Build whatever combination makes sense for what you're tracking down.

Some ps Options and Flags

You probably know ps aux. Maybe ps -ef if you're fancy. But ps has way more options than most people realize, and some of them matter when your server starts acting weird.

Different flags help with various problems. Sometimes you want everything sorted by memory usage. Other times, you need to see process relationships or filter by user. The standard commands don't always cut it.

Here's what actually works when you need more than the basics:

Basic Output Formats

ps (no options) shows processes in your current terminal session. Just your shell and whatever you're running right now.

ps -f gives you full format output. Adds parent process ID (PPID), start time, and command arguments. Useful for seeing the complete command line that started each process.

ps -l switches to long format. Shows process priority, nice values, memory info, and process state flags. More technical details than most people need daily.

ps -j displays job control format. Includes process group ID and session ID. Helpful for understanding how processes relate to terminal sessions.

ps -u shows user-oriented format. Similar to what you get with the 'u' in ps aux, displaying username, CPU/memory percentages, and readable timestamps.

ps -v gives virtual memory format. Focuses on memory statistics like page faults and swap usage. Good for memory troubleshooting.

ps aux combines BSD-style options. Shows all processes (a), user format (u), and includes processes without terminals (x). The most common ps command you'll use.

Process Selection Options

ps -e or ps -A shows every process on the system. Same result as ps aux but different syntax style.

ps -a displays all processes except session leaders and processes not associated with terminals. Less inclusive than -e.

ps -x includes processes without controlling terminals. Daemons and background services need this flag to appear.

ps -d shows all processes except session leaders. Excludes the main shell processes but includes everything else.

ps -N or ps --deselect shows processes that don't match your other selection criteria. Inverts your selection.

ps -T shows all processes on this terminal. More inclusive than the default ps with no options.

ps -r displays only running processes. Filters out sleeping, stopped, and zombie processes.

User and Group Selection

ps -u username shows processes owned by a specific user. Works with usernames or numeric user IDs.

ps -u user1,user2,user3 accepts multiple users separated by commas. No spaces between the names.

ps -U username similar to -u but uses real user ID instead of effective user ID. Matters when processes change their user context.

ps -g groupname shows processes belonging to a specific group. Group names or numeric group IDs both work.

ps -G groupname uses real group ID instead of effective group ID. Like -U vs -u distinction.

ps --user username GNU-style equivalent of -u. Longer to type but more readable in scripts.

ps --Group groupname GNU-style group selection.

Process ID Selection

ps -p 1234 shows a specific process by ID. You can check if a process still exists or get details about one particular process.

ps -p 1234,5678,9012 accepts multiple process IDs separated by commas.

ps --pid 1234 GNU-style syntax for the same thing.

ps -C nginx shows all processes with "nginx" as the command name. Saves you from piping to grep.

ps -C nginx,apache2,mysql works with multiple command names.

ps --ppid 1234 shows all children of process 1234. Great for seeing what a parent process has spawned.

Terminal Selection

ps -t pts/0 shows processes attached to a specific terminal. Use the actual terminal device name.

ps -t pts/0,pts/1 works with multiple terminals.

ps -t console shows processes on the system console.

ps --tty pts/0 GNU-style terminal selection.

Session and Process Group Selection

ps -s 1234 shows processes in a specific session. Sessions group related processes together.

ps --sid 1234 GNU-style session selection.

ps -g 1234 can also select by process group ID (when you use numeric IDs instead of group names).

Custom Output Formats

ps -o pid,user,cmd lets you specify exactly which columns appear. Mix and match any available fields.

ps -o pid,ppid,user,%cpu,%mem,cmd common combination for monitoring resource usage.

ps -O pid,cmd adds extra columns to the default format instead of replacing it entirely.

ps --format pid,user,cmd GNU-style custom formatting.

Available Output Fields

You can use these field names with -o or --format:

pid - Process ID

ppid - Parent process ID

user - Username

uid - User ID number

group - Group name

gid - Group ID number

comm - Command name only

cmd or command - Full command line

args - Command arguments

%cpu - CPU usage percentage

%mem - Memory usage percentage

rss - Resident memory size

vsz - Virtual memory size

size - Memory size in pages

time - Total CPU time

etime - Elapsed time since start

lstart - Full start time

stime - Start time

tty - Terminal

stat - Process state

nice - Nice value

pri - Priority

psr - Processor number

Sorting Options

ps aux --sort=pid sorts by process ID (roughly chronological).

ps aux --sort=-%cpu sorts by CPU usage, highest first. The minus reverses the order.

ps aux --sort=%cpu sorts by CPU usage, lowest first.

ps aux --sort=-%mem sorts by memory usage, highest first.

ps aux --sort=user sorts alphabetically by username.

ps aux --sort=start sorts by start time.

ps aux --sort=%cpu,-%mem sorts by multiple fields. CPU first, then memory within each CPU group.

ps --sort=-rss sorts by resident memory size, largest first.

Tree and Hierarchy Views

ps --forest or ps f shows process trees with ASCII art lines connecting parents to children.

ps axf combines showing all processes with forest view.

ps -ejH shows hierarchy through indentation instead of ASCII art.

ps -H shows process hierarchy with simple indentation.

Thread Options

ps -L shows threads as separate lines. Multi-threaded processes appear multiple times.

ps -T shows threads (different from the terminal -T option depending on context).

ps m shows threads below each process.

ps H shows threads as if they were processes.

Width and Header Control

ps -w prevents output lines from wrapping. Shows more of long command lines.

ps -ww removes width limits entirely. Very long command lines display completely.

ps --no-headers removes the column header line. Useful for scripts.

ps --headers forces headers even when output goes to files or pipes.

ps --cols 120 sets output width to specific number of columns.

Miscellaneous Useful Options

ps --help shows all available options. Different on different systems.

ps --version displays ps version information.

ps k %cpu or ps --sort %cpu alternative sorting syntax on some systems.

ps r shows only running processes (BSD style).

ps s shows signal format (shows pending signals).

ps c shows true command name rather than full path.

These are the core ps options that actually work across most Linux systems. The exact availability might vary slightly between distributions, but these represent the reliable, documented options you can count on.

Practical ps Usage Patterns

You've got the commands down. But knowing syntax doesn't help when your server's choking and users are complaining. Here's how you actually use this stuff when things break.

When Everything Slows Down

Your server feels sluggish. Load average is climbing. Something's wrong, but what?

Check the obvious stuff first. Run your CPU sort and see if one process is chewing through cycles. Sometimes it's that simple: a runaway import script or a backup that's stuck in a loop.

But if the top processes look normal, dig deeper. Count your web server workers. Apache usually runs 8-12 processes on a typical site. If you're seeing 40+ workers, either traffic spiked or something's preventing workers from finishing requests.

PHP-FPM pools tell their own story. Each pool should maintain steady worker counts. When you see all workers busy for extended periods, requests are backing up somewhere. Check the start times - if every worker spawned in the last few minutes, something caused a reset.

Database Connection Nightmares

Database connection limits hit you fast and hard. One minute everything works fine, the next minute new connections fail.

PostgreSQL makes this easy to spot. Each connection gets its own process, so counting postgres processes tells you exactly how many connections you have. Compare that number to your max_connections setting.

MySQL hides connections inside threads, but you can still catch problems. The main mysqld process grows when connections accumulate. If that process started small this morning and now shows 2GB RSS, connections aren't closing properly.

Watch for connection patterns that don't make sense. Your application normally holds 10-15 database connections. If ps shows 200+ connections during normal traffic, something's leaking connections or failing to close them.

Scripts Gone Wild

Cron jobs should run and finish. When they don't, they pile up and compete for resources.

Check script ages with the etime column. Your backup script normally finishes in 20 minutes. If it's been running for 6 hours, either the backup grew huge or something's broken.

Multiple instances of the same script usually mean trouble. Cron launched a new copy before the previous one finished. This happens when scripts take longer than their scheduled interval.

Look for scripts running as unexpected users. Root shouldn't run application backups. The www-data user shouldn't run system maintenance scripts. Wrong permissions cause weird failures.

Memory Creep

Memory leaks sneak up on you. RSS numbers grow slowly until swap kicks in and performance dies.

Watch the same process over time. That PHP worker started with 45MB an hour ago. Now it's using 180MB. That's not normal growth... that's a leak.

Process multiplication can mask memory problems. Instead of one process using 500MB, you might see five processes each using 100MB. Both patterns indicate problems, just different kinds.

Virtual memory (VSZ) numbers can mislead you. A process might allocate 1GB but only touch 50MB. Focus on RSS for actual memory consumption.

Web Server Weirdness

Web servers have predictable behaviors. When those patterns break, you know something changed.

Nginx should always show one master process as root and several workers as www-data. Missing masters mean nginx isn't actually running, despite what systemctl claims.

Apache process counts vary with traffic, but they shouldn't swing wildly. Steady growth in worker count suggests requests aren't completing. Sudden drops might indicate crashes or memory pressure killing workers.

Check process states when web servers act up. Workers stuck in 'D' state are waiting for disk I/O. Multiple workers in this state suggest storage problems or full disks.

Security Red Flags

Weird processes often indicate security issues or configuration problems.

Web applications shouldn't run as root. If you see PHP scripts or Python apps running with root privileges, someone misconfigured something or worse.

Unknown processes deserve investigation. You know what normally runs on your server. When ps shows processes you don't recognize, figure out what they are and why they're there.

Check network service processes during suspected attacks. Unusual numbers of SSH processes might indicate brute force attempts. Multiple instances of web servers could signal someone trying to exploit vulnerabilities.

Emergency Triage

When everything breaks at once, you need information fast.

Count critical processes first. Nginx master, MySQL daemon, PHP-FPM master - if these are missing, nothing else matters until you restart them.

Look for recent process starts. If everything began within the last few minutes, something caused a system-wide restart. Check logs for kernel panics or power issues.

Find the biggest resource consumers immediately. One process eating 80% CPU can bring down an entire server. Kill it first, ask questions later.

Building Your Own Patterns

Every server environment develops its own normal patterns. Learn yours. Monitor during different times of day. Your eCommerce site probably shows different process patterns during business hours versus late night. Know what busy looks like versus quiet.

Document what broke before. Keep notes about past outages and their process table signatures. Pattern recognition speeds up future troubleshooting.

Test your assumptions regularly. Run ps during known-good times and save the output. When problems arise, compare current state with your baseline.

The process table doesn't lie. Services might claim they're running fine, but ps shows you what's actually happening. Trust what you see over what you're told.

Scripting with ps

You can't babysit your server all day. Eventually, you need scripts that watch processes and yell when something breaks. ps outputs clean, predictable data that scripts can parse easily.

Building process monitors beats manually checking things every few hours. That MySQL connection leak from last month? Script it. PHP workers that multiply overnight? Catch it automatically.

Basic Service Checks

Start simple. Check if your web server actually runs:

#!/bin/bash

NGINX_COUNT=$(ps aux | grep -c '[n]ginx: master')

if [ $NGINX_COUNT -eq 0 ]; then
    echo "ALERT: Nginx master process missing"
    exit 1
fi

echo "Nginx running normally"

The [n]ginx bracket trick stops grep from matching itself. Without brackets, grep shows up as grep nginx in the process list.

Watch multiple services at once:

#!/bin/bash

check_service() {

    SERVICE=$1

    PATTERN=$2

    COUNT=$(ps aux | grep -c "$PATTERN")

    if [ $COUNT -eq 0 ]; then

        echo "CRITICAL: $SERVICE down"

        return 1

    else

        echo "OK: $SERVICE running ($COUNT processes)"

        return 0

    fi

}


FAILURES=0

check_service "Nginx" '[n]ginx: master' || ((FAILURES++))

check_service "MySQL" '[m]ysqld' || ((FAILURES++))

check_service "PHP-FPM" '[p]hp-fpm: master' || ((FAILURES++))


[ $FAILURES -gt 0 ] && exit 1

Watching Resource Usage

Memory and CPU problems sneak up on you. Parse ps output to catch them early:

#!/bin/bash


# Hunt down memory hogs over 80%

ps aux --no-headers | awk '$4 > 80 {print $2, $1, $4"% MEM", $11}' | while read PID USER MEM CMD; do

    echo "Memory hog found: PID $PID ($USER) eating $MEM - $CMD"

done


# Spot CPU burners over 50%

ps aux --no-headers | awk '$3 > 50 {print $2, $1, $3"% CPU", $11}' | while read PID USER CPU CMD; do

    echo "CPU burner: PID $PID ($USER) using $CPU - $CMD"

done

Build something that logs problems instead of just printing them:

#!/bin/bash


LOG_FILE="/var/log/resource_alerts.log"

TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')


log_problem() {

    echo "[$TIMESTAMP] $1" >> $LOG_FILE

    echo "$1"

}


# System load getting crazy?

LOAD=$(uptime | awk -F'load average:' '{print $2}' | awk -F',' '{print $1}' | tr -d ' ')

LOAD_INT=$(echo "$LOAD * 100" | bc | cut -d. -f1)


[ $LOAD_INT -gt 500 ] && log_problem "Load average hit $LOAD"


# Too many processes running?

PROCESS_COUNT=$(ps aux --no-headers | wc -l)

[ $PROCESS_COUNT -gt 300 ] && log_problem "Process count: $PROCESS_COUNT"


# Zombie apocalypse?

ZOMBIE_COUNT=$(ps aux | awk '$8 ~ /Z/ {print $2}' | wc -l)

if [ $ZOMBIE_COUNT -gt 0 ]; then

    log_problem "Found $ZOMBIE_COUNT zombie processes"

    ps aux | awk '$8 ~ /Z/ {print "  PID " $2 " PPID " $3 " CMD " $11}' >> $LOG_FILE

fi

Application Monitoring

Web apps follow patterns. When patterns break, you know something changed.

PHP-FPM pools should stay within reasonable limits:

#!/bin/bash


watch_php_pool() {

    POOL_NAME=$1

    MAX_WORKERS=$2

    ACTIVE=$(ps aux | grep -c "[p]hp-fpm: pool $POOL_NAME")

    if [ $ACTIVE -eq 0 ]; then

        echo "ERROR: Pool $POOL_NAME has zero workers"

        return 1

    fi

    if [ $ACTIVE -ge $MAX_WORKERS ]; then

        echo "WARNING: Pool $POOL_NAME maxed out ($ACTIVE/$MAX_WORKERS)"

        return 1

    fi

    echo "Pool $POOL_NAME looks good: $ACTIVE/$MAX_WORKERS workers"

    return 0

}

watch_php_pool "www" 50
watch_php_pool "api" 20

Database connections tell their own story:

#!/bin/bash


# PostgreSQL shows each connection as a separate process

PG_CONNECTIONS=$(ps aux | grep -c '[p]ostgres.*:.*')
PG_MAX=100

if [ $PG_CONNECTIONS -gt $((PG_MAX * 80 / 100)) ]; then

    echo "PostgreSQL connections getting high: $PG_CONNECTIONS/$PG_MAX"

fi


# MySQL hides connections in threads, but memory usage gives clues

MYSQL_RSS=$(ps aux | grep '[m]ysqld' | awk '{print $6}')

if [ ! -z "$MYSQL_RSS" ]; then

    # Rough math: each connection eats 1-2MB

    ESTIMATED=$((MYSQL_RSS / 1500))

    echo "MySQL memory suggests ~$ESTIMATED connections (${MYSQL_RSS}KB RSS)"

fi

Smart Restarts

Scripts can restart dead services, but be careful. Flapping services often indicate deeper problems:

#!/bin/bash

restart_if_dead() {

    SERVICE=$1
    PATTERN=$2
    SYSTEMD_NAME=$3   

    if ! ps aux | grep -q "$PATTERN"; then

        echo "$SERVICE appears dead, restarting..."

        systemctl restart $SYSTEMD_NAME

        sleep 5

        if ps aux | grep -q "$PATTERN"; then

            echo "$SERVICE back online"

        else

            echo "FAILED: $SERVICE won't start"

            return 1

        fi

    fi

}​​​​​​​
restart_if_dead "Nginx" '[n]ginx: master' "nginx"
restart_if_dead "PHP-FPM" '[p]hp-fpm: master' "php8.1-fpm"

Process Snapshots

Sometimes you need to see what changed between two points in time:

#!/bin/bash


SNAPSHOT_DIR="/tmp/ps_history"

mkdir -p $SNAPSHOT_DIR


CURRENT="$SNAPSHOT_DIR/snapshot_$(date +%s).txt"

PREVIOUS=$(ls -t $SNAPSHOT_DIR/snapshot_*.txt 2>/dev/null | head -1)


ps aux --sort=-%cpu > $CURRENT


if [ -f "$PREVIOUS" ]; then

    echo "Changes since last snapshot:"

   

    # New processes

    echo "=== NEW ==="

    comm -13 <(awk '{print $2}' $PREVIOUS | sort) \

             <(awk '{print $2}' $CURRENT | sort) | \

    while read PID; do

        grep "^[^ ]* *$PID " $CURRENT

    done

   

    # Missing processes  

    echo "=== GONE ==="

    comm -23 <(awk '{print $2}' $PREVIOUS | sort) \

             <(awk '{print $2}' $CURRENT | sort) | \

    while read PID; do

        grep "^[^ ]* *$PID " $PREVIOUS

    done

fi


# Keep last 10 snapshots

ls -t $SNAPSHOT_DIR/snapshot_*.txt | tail -n +11 | xargs rm -f 2>/dev/null

Feeding Monitoring Systems

Your scripts should talk to whatever monitoring you already use. JSON works everywhere:

#!/bin/bash

if [ "$1" = "--json" ]; then

    cat << EOF

{

    "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",

    "nginx_count": $(ps aux | grep -c '[n]ginx'),

    "php_fpm_count": $(ps aux | grep -c '[p]hp-fpm'),

    "mysql_running": $(ps aux | grep -q '[m]ysqld' && echo true || echo false),

    "cpu_hogs": $(ps aux --no-headers | awk '$3 > 80' | wc -l),

    "memory_hogs": $(ps aux --no-headers | awk '$4 > 80' | wc -l),

    "zombies": $(ps aux | awk '$8 ~ /Z/' | wc -l),

    "total_procs": $(ps aux --no-headers | wc -l)

}

EOF

else

    echo "System Status - $(date)"

    echo "Nginx: $(ps aux | grep -c '[n]ginx') processes"

    echo "PHP-FPM: $(ps aux | grep -c '[p]hp-fpm') processes"  

    echo "Total: $(ps aux --no-headers | wc -l) processes"

fi

Alerts

Send notifications when things actually break:

#!/bin/bash


ALERT_EMAIL="admin@example.com"
SERVER=$(hostname)

send_alert() {

    SUBJECT="$1"

    MESSAGE="$2"

    echo "$MESSAGE" | mail -s "[$SERVER] $SUBJECT" $ALERT_EMAIL

    logger "PROCESS ALERT: $SUBJECT - $MESSAGE"

}

# Runaway CPU usage

ps aux --no-headers | awk '$3 > 90 {print $2, $1, $3, $11}' | while read PID USER CPU CMD; do

    send_alert "CPU Spike" "Process $PID ($CMD) as $USER hit $CPU% CPU"

done

# Memory leaks (over 1GB per process)

ps aux --no-headers | awk '$6 > 1000000 {print $2, $1, $6/1024, $11}' | while read PID USER MEM CMD; do

    send_alert "Memory Leak" "Process $PID ($CMD) as $USER using ${MEM}MB"

done

Quick heads-up: The mail command needs mailutils installed on Ubuntu. Most production servers have it, but if your alert script fails silently, check if it's missing.

Run which mail to verify, or install it with:

$ sudo apt install mailutils

You'll be asked about the mail server configuration during the installation for local alerts; "Local only" works fine.

Now here's the catch... if you're trying to send alerts to external addresses, you'll hit a wall. Pretty much every reputable VPS provider (Webdock included) blocks port 25 and other mail ports by default. Too many spammers ruined it for everyone.

However, if you're on Webdock (and running anything above their $5.99 plan), they include Postmark's transactional email service at no extra charge (fair use applies). The pros use Postmark for transactional or system alerts and notifications.

Cron Integration

Set up automatic monitoring:

# sudo crontab -e
# Basic service health every 5 minutes
*/5 * * * * /usr/local/bin/service_check.sh

# Resource monitoring every 15 minutes  
*/15 * * * * /usr/local/bin/resource_watch.sh

# Process diff snapshots hourly
0 * * * * /usr/local/bin/process_snapshot.sh

# Daily summary at 6 AM
0 6 * * * /usr/local/bin/daily_report.sh​​​​​​​

Start with simple service checks. Add complexity as you learn what breaks on your servers. Good process monitoring catches problems before users notice them.

Wrapping Up: ps in the Real World

I hope you know the power of the simple ps command now. The syntax, the flags, the patterns that matter when servers misbehave. But ps gets better with practice, not memorization. Your server will teach you things no guide can.

Build your own shortcuts. Maybe you'll always sort by memory usage first, or you prefer watching specific users. Everyone develops their own ps habits based on what breaks most often in their environment.

Your monitoring tools will fail sometimes. Networks go down, agents crash, dashboards break. ps always works because it reads directly from the kernel. When everything else stops reporting, ps keeps showing you the truth!

Meet Aayush, a WordPress website designer with almost a decade of experience who crafts visually appealing websites and has a knack for writing engaging technology blogs. In his spare time, he enjoys illuminating the surrounding minds.

chat box icon
Close
combined chatbox icon

Welcome to our Chatbox

Reach out to our Support Team or chat with our AI Assistant for quick and accurate answers.
webdockThe Webdock AI Assistant is good for...
webdockChatting with Support is good for...