📋 ps Quick Reference

cheat sheet / survival guide

Video: ps Cheat Sheet (sysadmin video)
Prefer to watch? This video runs the guide's main commands on a real Ubuntu 24.04 machine, with on-screen captions and no voiceover. Click to play, or watch it on YouTube. It is part of the Troubleshooting and Performance playlist.
ps [options]
ps aux

ps takes a SNAPSHOT of the processes running on the system: who started them, how much CPU and memory they use, how long they have been running, and the exact command line. Use it to find
what is running, hunt runaway or stuck processes, find the parent of a process, check who owns what, and feed process lists into scripts. Unlike top and htop (live views), ps prints once and
exits, which makes it perfect for scripts and pipelines. This sheet covers the everyday commands, choosing columns, sorting, filtering, threads and trees, process states, and one-liners.
It is written for Linux (procps-ng). macOS and BSD ps differ in places (noted at the end).

Three styles of options (this confuses everyone)

ps has grown three option styles that all work on Linux:
UNIX style     Options start with a dash, and can be grouped:             ps -ef        ps -eF        ps -u alice
BSD style      NO dash:                                                    ps aux        ps axjf       ps ax
GNU long       Two dashes and a word:                                     ps --forest   ps --sort=-%mem   ps --no-headers
Mixing them can change the meaning:  ps -aux  (with a dash) means "user x"... which prints a warning on Linux. Type  ps aux  for BSD style and  ps -ef  for UNIX style.
Most people memorize two commands:  ps aux  (BSD style, all processes with CPU and memory)   and   ps -ef  (UNIX style, all processes with parent PIDs).

The commands you will use most

ps                               # only YOUR processes in THIS terminal (a very short list: your shell and ps itself)
ps aux                           # every process on the system, with the user, CPU and memory: the classic
ps -ef                           # every process with the parent PID (PPID) and start time: the classic UNIX view
ps -eF                           # like -ef but with extra columns (size, RSS, the CPU it ran on)
ps -ef --forest                  # a tree: children drawn under their parents        ps axjf    the BSD style tree        pstree -p    a nicer tree tool
ps -u alice                      # processes of user alice (effective user)        ps -U alice   real user        ps -u root
ps -p 1234                       # one process by PID            ps -p 1234,5678    several          ps -p $$    my current shell
ps -C nginx                      # processes whose COMMAND NAME is exactly nginx         ps -C nginx,php-fpm
ps aux | grep '[n]ginx'          # search the full list. The [n] trick stops grep from matching itself
ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head        # a custom table sorted by CPU (see the next sections)
ps -o pid,cmd --ppid 1           # children of a given parent (here: PID 1, systemd)
ps -t pts/0                      # processes attached to a terminal          ps -t '?'    processes with no terminal (daemons: quote the ?)
ps -e --no-headers | wc -l       # how many processes are running
Tip: ps aux | less -S   keeps long lines from wrapping. Use  ps auxww  so the command line is NOT cut at the terminal width.

Reading the output of ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1 168584 12960 ?        Ss   Sep25   0:07 /sbin/init
alice     2311  1.2  2.4 2846712 391604 ?      Sl   09:14   1:05 /usr/lib/firefox/firefox
USER      Who owns (started) the process
PID       The process ID: a unique number. Use it with kill, renice, strace, lsof -p, and /proc/PID
%CPU      CPU time used divided by the time the process has been running (a LIFETIME AVERAGE, not the current usage). A process that was busy earlier can still show a high number. For live CPU use top or htop
%MEM      The share of physical memory (RAM) the process occupies (resident set size)
VSZ       Virtual size in KB: all the address space the process has mapped. It is often huge and not a good measure of memory use
RSS       Resident Set Size in KB: RAM the process is using now. This is the number to look at for memory. Shared libraries are counted in every process that uses them, so RSS totals can exceed real RAM
TTY       The terminal the process is attached to (pts/0, tty1). A ? means no terminal (a daemon or service)
STAT      The state of the process (see below)
START     When it started (a time for today, or a date)
TIME      Total CPU time consumed, in minutes:seconds. Not the same as how long it has been running (that is ELAPSED / etime)
COMMAND   The command and its arguments (truncated to the screen width unless you use ww). Names in [brackets] are kernel threads, like [kworker/0:1]
In ps -ef the columns are:  UID PID PPID C STIME TTY TIME CMD.  PPID is the parent's PID. C is a recent CPU usage figure.

Process states (the STAT column)

Main letter:
R   Running or runnable (using CPU or waiting for a turn)
S   Sleeping, waiting for something (interruptible). Most processes are in this state most of the time. Normal
D   Uninterruptible sleep, usually waiting on disk or network I/O (NFS, a failing disk). It cannot be killed until the I/O finishes. Many D processes = an I/O problem
T   Stopped (Ctrl+Z, or a debugger, or SIGSTOP). Resume with kill -CONT PID or fg
t   Stopped by a debugger during tracing
Z   Zombie: finished, but its parent has not collected its exit status yet. It uses no CPU or memory, only a process table entry. Fix the parent (or restart it)
I   Idle kernel thread (newer kernels)         X  Dead (you should never see this)
Extra characters after the letter:
s   Session leader             <   High priority (nice value below 0)          N   Low priority (nice above 0)          L   Has pages locked in memory
l   Multi-threaded             +   In the foreground of its terminal            W   Swapped out (old kernels)
Example:  Ssl = sleeping, session leader, multi-threaded.   R+ = running in the foreground.   D = stuck in I/O.   Z or Z+ = zombie.
Find problem states:
ps -eo stat,pid,ppid,user,cmd | awk '$1 ~ /^D/'          # processes stuck in uninterruptible sleep (I/O problems)
ps -eo stat,pid,ppid,user,cmd | awk '$1 ~ /^Z/'          # zombies (then look at their PPID: the parent is the one to fix)
ps -eo stat,pid,ppid,cmd | awk '$1 ~ /^T/'               # stopped jobs

Choose your own columns: -o

ps -eo pid,ppid,user,%cpu,%mem,rss,etime,cmd             # a useful everyday view
ps -o pid=,cmd= -p 1234                                  # a trailing = removes the header for that column (script friendly)       ps -o rss= -p 1234    just the memory number
ps -eo pid:8,user:12,comm:20,args                        # set column widths with :N
Common column names (-o):
pid          Process ID                                    ppid       Parent process ID                     pgid / sid    Process group / session ID
user         Effective user name (uid for the number)      euser  ruser  Effective / real user                group    Group name
%cpu  pcpu   CPU% over the process lifetime                %mem  pmem   Memory %                           rss    Resident memory (KB)      vsz    Virtual memory (KB)
etime        Elapsed time since it started ([[dd-]hh:]mm:ss)     etimes   the same in seconds                lstart   Full start date and time          start_time    start time (short)
time         Cumulative CPU time                           stat  state   The state                          nice  ni    Nice value (-20 high priority to 19 low)       pri    priority
comm         Command name only (no arguments, max 15 characters)      cmd  args   The full command line      command    the full command as typed        exe   path of the executable
tty          Terminal                                      nlwp  thcount   Number of threads              psr    The CPU core it last ran on          wchan   The kernel function it is waiting in (why it sleeps)
tid          Thread ID (with -L)                           uid  gid       Numeric IDs                       lwp    Thread ID (same as tid)              sgi_p    CPU running on now (R state)
cgroup       Control groups (containers, systemd services)      unit   The systemd unit of the process      slice   the systemd slice          ouid  the login user's UID
List every available column:  ps L
Numeric and shell-friendly output (no name lookups):  ps -eo uid,pid,cmd
Wide command lines:  ps -eo pid,args -ww     (-w wide, -ww unlimited)      Or set the width:  COLUMNS=250 ps aux

Sorting and top-N lists

ps aux --sort=-%cpu | head -10                           # top CPU users (- means descending)      remember %cpu is a lifetime average
ps aux --sort=-%mem | head -10                           # top memory users
ps aux --sort=-rss | head -10                            # sort by real memory (RSS)
ps -eo pid,user,%mem,rss,cmd --sort=-rss | head -15      # a neat top-15 memory table
ps -eo pid,etime,cmd --sort=-etime | head                # the longest-running processes (oldest first)         --sort=etime    the newest
ps -eo pid,lstart,cmd --sort=lstart | tail -5            # the most recently started processes
ps -eo pid,nlwp,cmd --sort=-nlwp | head                  # the processes with the most threads
ps -eo pid,%cpu,%mem,cmd --sort=-%cpu,-%mem | head       # sort by several keys: CPU first, then memory
Sort keys work with any column name:  --sort=pid  --sort=user  --sort=-vsz  --sort=start_time.
For a live sorted view use top -o %CPU, htop, or  watch -n 2 'ps aux --sort=-%cpu | head'.

Filter and select

ps -u alice -o pid,%cpu,%mem,cmd                         # one user's processes         ps -U alice -u alice    real and effective
ps -C sshd -o pid,ppid,user,cmd                          # by exact command name
ps -p $(pgrep -d, nginx) -o pid,ppid,%cpu,%mem,cmd       # feed pgrep's PIDs to ps (-d, joins them with commas)
ps --ppid 1234 -o pid,cmd                                # direct children of PID 1234
ps -g 1234                                               # a process group          ps -s 1234    a session          ps --sid 1234
ps -eo pid,user,cmd | awk '$2=="www-data"'               # filter columns with awk
ps -eo user | sort | uniq -c | sort -rn                  # how many processes each user has
ps -eo comm | sort | uniq -c | sort -rn | head           # which programs run the most instances
ps -e -o pid,comm | grep -E 'nginx|apache|httpd'          # web servers
ps -N -u root -o pid,user,cmd                            # everything EXCEPT root's processes (-N negates)
pgrep and pkill are often better for name searches (below).

Threads

ps -eLf                                                  # every THREAD (LWP column) with a line each          ps -L -p 1234    the threads of one process
ps -eLo pid,tid,psr,%cpu,stat,comm | head                # thread ID, and which CPU core it ran on
ps -o pid,nlwp,cmd -p 1234                               # the thread count of one process (nlwp)
ps -eLf | wc -l                                          # total threads on the system       cat /proc/sys/kernel/threads-max    the limit
ps -T -p 1234                                            # the threads of a process (SPID column)          ps H -p 1234    the BSD style
A process with thousands of threads or a steadily growing thread count often signals a leak. Compare with  ulimit -u  and the systemd TasksMax setting.

Trees and parents (who started what)

ps -ef --forest                                          # a tree view with ASCII lines             ps auxf    BSD style tree              ps -eo pid,ppid,cmd --forest
ps -ejH                                                  # process tree with session and group IDs (indented)
pstree -p                                                # a nicer tree (sudo apt install psmisc)          pstree -ap 1234    a subtree with arguments          pstree -u alice    one user's processes
ps -o ppid= -p 1234                                      # the PARENT PID of a process          ps -o pid,ppid,cmd -p $(ps -o ppid= -p 1234)    who is the parent?
Following the parent chain finds the real culprit: an orphan (PPID 1) often means a daemon or a process whose parent exited. Zombies are cleared by fixing their PARENT, not by killing the zombie.
systemd view:  systemctl status PID   or  systemd-cgls   shows which service a process belongs to           ps -o pid,unit,slice,cmd -p PID

Time: how long has it been running?
ps -o pid,etime,cmd -p 1234                              # elapsed time since it started:  03-04:21:07 = 3 days 4 hours 21 minutes 7 seconds
ps -o pid,etimes= -p 1234                                # elapsed seconds (great for scripts)
ps -o pid,lstart -p 1234                                 # the full start date and time             ps -o pid,start_time -p 1234
ps -eo pid,etimes,cmd | awk '$2 > 86400 {print}'          # everything running more than a day
ps -eo pid,etime,cmd --sort=etime | tail                 # the oldest processes
ps -o pid,time,cmd -p 1234                               # total CPU TIME used (not elapsed): 12:34 means 12 minutes of CPU
Started long ago and still using a lot of CPU TIME: a candidate for a leak or a busy loop. Started long ago, TIME small: an idle, healthy service.

Memory and CPU: what is really being used

ps -eo pid,user,rss,vsz,%mem,cmd --sort=-rss | head       # RSS (real RAM) versus VSZ (address space)
ps -o rss= -p 1234 | awk '{printf "%.1f MB\n", $1/1024}'    # one process, in MB
ps -eo rss= | awk '{s+=$1} END {printf "%.1f MB total RSS\n", s/1024}'              # a rough total (double counts shared memory)
ps -eo user=,rss= | awk '{a[$1]+=$2} END {for (u in a) printf "%-12s %8.1f MB\n", u, a[u]/1024}' | sort -k2 -rn        # memory per user
ps -eo comm=,rss= | awk '{a[$1]+=$2} END {for (c in a) printf "%-20s %8.1f MB\n", c, a[c]/1024}' | sort -k2 -rn | head       # memory per program (all its processes together)
Better memory numbers than RSS (shared pages counted once):  smem -tk    or    grep -E 'Pss|Rss' /proc/PID/smaps_rollup     and system totals with  free -h
CPU: %cpu in ps is an AVERAGE since the process started. For what is happening NOW use  top -b -n1 | head -20 ,  pidstat 1 5 -p PID  (sysstat), or  htop.
Out-of-memory kills:  dmesg -T | grep -i 'killed process'    journalctl -k | grep -i oom     ps shows the survivors: the victim is the process with the highest oom_score:  cat /proc/PID/oom_score

Priority and scheduling

ps -eo pid,ni,pri,cls,rtprio,cmd | head                  # nice value (ni), priority, and scheduling class (TS = normal, FF/RR = real time)
ps -eo pid,ni,cmd --sort=ni | head                       # the lowest nice value (highest priority) first
renice -n 10 -p 1234                                     # lower the priority of a running process       sudo renice -n -5 -p 1234    raise it        nice -n 10 command    start a command with lower priority
ionice -p 1234 ; ionice -c3 -p 1234                      # I/O scheduling class (idle = 3) for disk-heavy processes
taskset -cp 1234                                         # which CPU cores it may use          ps -o pid,psr,cmd -p 1234    the core it last ran on
A nice value of 19 is the lowest priority, -20 the highest. Only root can lower the value (raise the priority).

Environment, files and the /proc filesystem

ps eww -p 1234                                           # show the process's ENVIRONMENT variables after the command (e = environment, ww = do not truncate)        may show secrets: be careful
sudo cat /proc/1234/environ | tr '\0' '\n'               # the same from /proc (root or the owner)
cat /proc/1234/cmdline | tr '\0' ' '; echo               # the exact command line       cat /proc/1234/status    state, memory, threads, capabilities, UIDs         readlink /proc/1234/exe    the executable
ls -l /proc/1234/fd | head                                # the files and sockets it has open        ls -l /proc/1234/cwd    its working directory         cat /proc/1234/limits    resource limits         cat /proc/1234/cgroup
sudo lsof -p 1234                                        # the same and more: files, sockets, libraries (see the lsof sheet)          sudo ss -tunp | grep 1234    network sockets of a PID
sudo strace -p 1234 -f -tt -e trace=network              # what is it doing right now? (see the strace sheet)                           cat /proc/1234/wchan; echo    the kernel function it sleeps in
ps -o pid,wchan:20,cmd -p 1234                           # why a D-state process is stuck (for example nfs_... or io_schedule)
Command lines are visible to every user (ps aux). NEVER pass passwords or tokens as command-line arguments: any user on the machine can read them, and they end up in logs. Use files, environment variables, or prompts instead.
On hardened systems:  mount -o remount,hidepid=2 /proc   hides other users' processes from non-root users.

pgrep, pkill and pidof: find and signal by name
pgrep nginx                                              # PIDs of processes whose NAME contains "nginx"          pgrep -x sshd    exact name         pgrep -l nginx    with names          pgrep -a nginx    with the full command line
pgrep -f "python3 app.py"                                # match against the FULL command line (needed for scripts run by an interpreter)
pgrep -u alice                                           # a user's processes          pgrep -u root sshd    combine          pgrep -c nginx    just count them
pgrep -n firefox   pgrep -o firefox                      # the newest / oldest match
pgrep -P 1234                                            # children of PID 1234          pgrep -t pts/1    on a terminal
pkill nginx                                              # send SIGTERM (ask nicely) to every match          pkill -f "app.py"    match the full command line          pkill -u alice    all of a user's processes
pkill -9 -f runaway.sh                                   # SIGKILL: last resort (no clean-up)          pkill -HUP nginx    reload (many daemons re-read config on HUP)
pidof nginx                                              # PIDs of a program by name (simple)         pidof -s nginx    just one PID
kill 1234 ; kill -15 1234 ; kill -TERM 1234              # ask the process to stop (SIGTERM, the default)          kill -9 1234    force (SIGKILL)         kill -HUP 1234    reload          kill -0 1234 && echo alive    is it still there?
kill -STOP 1234 ; kill -CONT 1234                        # pause and resume a process
killall firefox                                          # by name (on Linux: all processes with that exact name; careful: on Solaris killall means kill EVERYTHING)
Signals: 15 TERM (polite, the default)  9 KILL (cannot be caught)  1 HUP (reload/hangup)  2 INT (Ctrl+C)  3 QUIT  19/18 STOP/CONT  10/12 USR1/USR2 (app-defined)   List them:  kill -l
Try TERM first and wait a few seconds. KILL leaves temporary files, locks and shared memory behind. A process in D state ignores signals until its I/O returns.
Always check what you match BEFORE you kill:  pgrep -a pattern   shows exactly what pkill pattern would hit. A pattern like  pkill -f java  can hit unrelated programs.

Containers, services and cgroups

ps -eo pid,cgroup:60,cmd | head                          # which cgroup (systemd unit or container) each process is in
ps -eo pid,user,cmd,cgroup | grep -E 'docker|containerd|kubepods'          # find container processes from the HOST
ps -ef | grep -v grep | grep containerd-shim              # Docker/containerd shim processes (one per container)
docker top mycontainer                                   # ps-style list of a container's processes        docker exec mycontainer ps aux    (only if ps exists in the image; many minimal images lack it: use /proc)
systemctl status nginx                                   # a service's processes in a tree, with the main PID          systemd-cgls    the whole cgroup tree          systemd-cgtop    live usage by service
A process seen from the host has a different PID than inside its container (PID namespaces). Use  docker inspect -f '{{.State.Pid}}' NAME  to get the host PID, then  ps -p PID .
Minimal containers (Alpine/BusyBox) have a reduced ps that lacks many options: check what it offers with  ps --help  or read /proc directly.

Practical one-liners

# What is eating my CPU and memory right now?
ps -eo pid,user,%cpu,%mem,rss,etime,cmd --sort=-%cpu | head -10 ; echo ; ps -eo pid,user,%cpu,%mem,rss,etime,cmd --sort=-%mem | head -10

# Everything belonging to a service, in a tree
ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --forest | grep -A5 '[n]ginx'

# Kill a process you found by name, safely (show first, then kill)
pgrep -a myapp ; read -r -p "Kill these? [y/N] " a && [ "$a" = y ] && pkill myapp

# Find zombies and their parents
ps -eo stat,pid,ppid,user,cmd | awk '$1 ~ /^Z/ {print; system("ps -o pid,cmd -p " $3)}'

# Find processes in uninterruptible sleep and why
ps -eo stat,pid,wchan:22,cmd | awk '$1 ~ /^D/'

# Who is running what? (count per user)
ps -eo user= | sort | uniq -c | sort -rn

# Processes running for more than 7 days
ps -eo pid,etimes,user,cmd | awk '$2 > 604800 {printf "%s %.1f days %s %s\n", $1, $2/86400, $3, substr($0, index($0,$4))}'

# The 5 processes with the most threads
ps -eLo pid,comm | sort | uniq -c | sort -rn | head -5

# Which process is using a port? (ps cannot tell you: use ss)
sudo ss -tulpn | grep ':8080'      then      ps -o pid,user,etime,cmd -p PID

# Watch the top CPU processes every 2 seconds
watch -n 2 'ps -eo pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -15'

# Show a process and its whole family (parent and all children)
pstree -ap $(pgrep -o nginx)        or        ps -o pid,ppid,cmd -p PID --ppid PID

# Get a process's full command line without truncation, on one line
ps -o args= -p 1234 -ww

# Count how many processes match a name
pgrep -c -x sshd

# Was a program started by cron or a person? Look at the parent
ps -o pid,ppid,user,cmd -p PID ; ps -o pid,cmd -p $(ps -o ppid= -p PID)

# Log a snapshot of the busiest processes every minute (cron)
* * * * * ps -eo pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -6 >> /var/log/top-cpu.log

# Show only processes older than a start time (kill idle sessions)
ps -eo pid,tty,etimes,user,cmd | awk '$2 ~ /pts/ && $3 > 28800'

# Simple watchdog: is my service running?
pgrep -x myservice >/dev/null || echo "myservice is DOWN"

macOS and BSD differences
ps -ax                                                   # every process on macOS/BSD (no dash: ps aux also works)         ps -axo pid,ppid,%cpu,%mem,etime,command    columns work, but the names differ slightly (command instead of cmd, no --sort or --forest)
ps -axo pid,%cpu,%mem,comm | sort -k2 -nr | head         # sort by piping to sort instead of --sort
ps -axo lstart,pid,command                               # start times          pgrep -lf pattern    also works on macOS
The GNU long options (--sort, --forest, --no-headers, --ppid) do NOT exist on macOS/BSD. Install GNU tools with brew install procps for the same behavior (the command is then  ps  from procps-ng).
BusyBox (Alpine) ps supports only a small set of options (-o pid,user,comm,args, and no --forest). Use /proc for more.

ps, top, htop and friends
ps            A one-off SNAPSHOT you can filter and script. Best for scripts, logs, pipelines, and asking exact questions
top           Live, interactive view of CPU and memory (press P for CPU sort, M for memory, 1 for each core, k to kill)
htop          A friendlier live view with trees, mouse, search and kill (see the htop sheet)
pgrep/pkill   Find and signal processes by name and attributes
pstree        A clear picture of parent and child relationships
pidstat       Per-process CPU, memory and I/O over time (sysstat package: pidstat -u -r -d 1)
lsof / ss     Which files and network ports a process has open (see the lsof sheet)
strace / perf What a process is doing right now (see the strace and perf sheets)
systemctl     For services: systemctl status NAME shows the main PID and its children

Common problems

"ps: warning: bad syntax, perhaps a bogus '-'"          You mixed styles (for example ps -aux). Use ps aux (no dash) or ps -ef
ps shows only a few processes                           You ran plain ps (only your terminal). Add  -e  or  aux
The COMMAND column is cut off                           Add  ww  (ps auxww) or use  -o args  with COLUMNS set. When piping, ps already stops truncating
grep shows itself in the results                        Use the bracket trick  grep '[n]ginx' , or use pgrep instead
%CPU shows more than 100%                               The process is multi-threaded and uses several cores (100% = one core). It is also a lifetime average
%CPU is high for a process that is idle now             %CPU is averaged over the process's whole life. Use top or pidstat to see the CURRENT usage
VSZ is huge but the machine has plenty of free memory   VSZ counts reserved address space, not used RAM (Java and browsers reserve a lot). Look at RSS
A zombie (Z) process will not go away                   You cannot kill a zombie: it is already dead. Restart or fix its PARENT (ps -o ppid= -p PID), and the parent will reap it, or PID 1 adopts it
kill does nothing                                       The process ignores TERM (send KILL, as a last resort), is in D state (waiting on I/O: fix the disk or NFS), or you lack permission (use sudo)
D-state processes pile up                               A stuck disk, an NFS server that is down, or a hung mount. Check dmesg, mount, and the wchan column; fix the storage
"ps: command not found" in a container                  The image has no procps. Install it (apt install procps) or read /proc: for p in /proc/[0-9]*; do echo "$p $(tr '\0' ' ' < $p/cmdline)"; done
The PID I see differs from the container's PID         PID namespaces. Find the host PID with docker inspect, or use docker top
My process does not appear                              It exited already, you are in another PID namespace (container), or hidepid hides it. Use sudo and check journalctl
Very long lines break my awk parsing                    Use -o with fixed columns and put cmd or args LAST so spaces in the command do not shift the fields
Different columns on different systems                  procps versions and BSD differ. Specify columns explicitly with -o so output is predictable in scripts
Times look wrong                                        START is in local time. TIME is CPU time, not elapsed. Use etime/etimes for elapsed time

Tips

    Remember two commands: ps aux (or ps auxww) for everything with CPU and memory, and ps -ef --forest for the parent and child tree.

    Use -o to choose exactly the columns you need (pid,ppid,user,%cpu,%mem,rss,etime,cmd), and put cmd last so awk parsing stays reliable.

    Read %CPU as a lifetime average. For what is happening now use top, htop or pidstat. Use RSS, not VSZ, for real memory use.

    Learn the STAT letters: R running, S sleeping, D stuck in I/O, T stopped, Z zombie. Fix zombies through the parent and D-state through the storage or network.

    Use pgrep -a pattern to see what a pkill would hit before you run it, and try SIGTERM before SIGKILL.

    Use etime and lstart to see how long something has really been running, and ppid with --forest or pstree to see who started it.

    Never put passwords or tokens on a command line: every user can read command lines in ps and /proc.

    In containers, use docker top or the host's ps with the cgroup column. Minimal images may not have ps at all: read /proc instead.

    Use watch -n 2 with ps for a quick live view, or log periodic snapshots with cron when you are chasing an intermittent problem.

    On macOS and BSD the GNU long options do not exist: pipe to sort or install GNU procps.