When you need to know which PID owns a stuck job, who is running a binary, or whether a script path is still alive, a one-shot process query beats a full-screen monitor. That is what ps and pgrep are for. ps prints a snapshot table you can read, sort, and paste into a ticket. pgrep returns matching PIDs (and optionally names) for scripts and pipelines.
Live dashboards belong elsewhere: top, htop, and btop watch CPU and RAM as they change. This article owns the query side — find a process by PID, user, memory footprint, or execution path, then move on.
Warm-up: your shell and a decoy process
Start with two known PIDs: your current shell, and a harmless background decoy you can hunt and remove.
Print your shell’s PID ($$ expands inside the shell):
echo $$
Start a decoy that will sit quietly for a few minutes, and note the PID the shell prints:
sleep 300 &
Inspect that PID with ps (replace 12345 with the number you saw):
ps -p 12345
Typical output:
PID TTY TIME CMD
12345 pts/0 00:00:00 sleep
When you are done practicing, clean up the decoy:
kill 12345
Note: If you forgot the PID, pgrep sleep (covered below) finds it again. Prefer killing only the decoy you started — not every sleep on a shared host.
Everyday snapshots
Two classic forms show almost every process. They differ mainly in column layout and heritage; both are fine for triage.
BSD-style snapshot (wide, includes %CPU and %MEM):
ps aux
System V-style snapshot (UID, PID, PPID, CMD):
ps -ef
Sample ps aux columns to read with intent:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
alice 12345 0.0 0.0 8900 720 pts/0 S 00:10 0:00 sleep 300
alice 2201 0.2 1.4 450000 56000 ? Ssl Jan04 3:12 /usr/bin/node server.js
USER and PID answer ownership. %MEM / RSS hint at memory weight. COMMAND / CMD is the short name or path — often truncated in the default width.
Note: Pipe to less or head when the list is huge. A full ps aux on a busy host is a firehose; filter as soon as you know a name, user, or PID.
Find PIDs with pgrep
When you only need “which PIDs match this name?”, pgrep is cleaner than ps | grep. It does not match its own grep line the way a naive pipeline can.
Find PIDs whose process name matches sleep:
pgrep sleep
Show PID and name:
pgrep -l sleep
Show PID and the full command line:
pgrep -a sleep
Typical -a output for the decoy:
12345 sleep 300
Compare with a fragile pipeline that often matches itself:
ps aux | grep sleep
Note: Prefer pgrep for name → PID. Use ps when you need CPU, memory, state, or custom columns in the same view.
Filter by user
On shared machines, limit the view to one account before you hunt by name.
Processes for a given user with ps:
ps -u alice
Same idea with pgrep (prints PIDs owned by that user; combine with a name pattern):
pgrep -u alice
pgrep -u alice sleep
For your own processes only:
ps -u "$USER"
pgrep -u "$USER" -a .
Note: -u on pgrep without a pattern lists every PID for that user. Add a name when you already know what you are hunting.
Rank by memory or CPU
Snapshots can answer “who is heavy right now?” without opening a monitor. Sort descending by memory or CPU and keep the top rows.
Highest memory first:
ps aux --sort=-%mem | head -n 15
Highest CPU first:
ps aux --sort=-%cpu | head -n 15
Note: These numbers are a moment in time. If the hot process changes every second, switch to top/htop for a live sort. Use ps --sort for a pasteable snapshot in a ticket or chat.
Full command and execution path
Default CMD columns often truncate. Ask for the full argument vector when you need the script path, config flag, or which copy of a binary is running.
Show full args for one PID:
ps -p 12345 -o pid,user,args
args and cmd both expand the command line; args is the usual choice in custom formats.
Match against the full command line with pgrep -f (not just the process name). Useful when many workers share a name but differ by path or flags:
pgrep -af 'node.*server.js'
pgrep -af '/usr/bin/python3.*/opt/app/'
Note: -f is powerful and easy to over-match. Anchor on a distinctive path or flag. Test with -a (list) before you pipe PIDs into anything destructive.
Custom columns
Build a ticket-friendly table with only the fields you care about. -o selects columns; comma-separated names define the row.
ps -eo pid,ppid,user,%mem,rss,stat,args --sort=-rss | head -n 20
Read RSS (resident set, kilobytes) as a concrete memory footprint; %MEM as a share of machine RAM. STAT letters encode state (R running, S sleeping, Z zombie, and more). PPID is the parent — useful when a reaper or supervisor owns a flock of workers.
For a single PID in the same shape:
ps -p 12345 -o pid,ppid,user,%mem,rss,stat,args
Note: Keep a short -o list you like and reuse it. Wide default dumps waste time; custom columns make the next paste readable.
Trees and parents
When dozens of workers share a name, parent/child structure clarifies which tree to restart.
Forest view (ASCII tree):
ps -ef --forest
Or hierarchical formatting:
ps -efH
Scroll to your service’s parent PID, then confirm children with pgrep or ps --ppid:
ps --ppid 2200 -o pid,user,args
Note: Reach for a forest view when “kill one worker” might be wrong and you need the supervisor PID instead. For open files or ports held by that PID, continue with lsof.
Quick reference card
Keep this nearby until the flags become muscle memory:
| Goal | Command |
|---|---|
| One PID | ps -p PID |
| All processes (BSD) | ps aux |
| All processes (SysV) | ps -ef |
| PIDs by name | pgrep name |
| Name + cmdline | pgrep -a name |
| Full cmdline match | pgrep -af 'pattern' |
| By user | ps -u user / pgrep -u user |
| Top memory | ps aux --sort=-%mem | head |
| Top CPU | ps aux --sort=-%cpu | head |
| Custom columns | ps -eo pid,user,%mem,rss,args |
| Full args for PID | ps -p PID -o pid,user,args |
| Process tree | ps -ef --forest |
Practice drills
Use your own shell and a fresh sleep 300 & decoy. Try these without peeking.
- Print your shell’s PID, then show a one-line
psview for it with user and full args. - Find the decoy with
pgrepso the full command line is visible. - List the ten highest-memory processes on the box.
- Show custom columns (
pid,user,%mem,rss,args) for the decoy’s PID. - Use
pgrep -fto match a distinctive substring of a real process’s path or args on your system (for examplebashorssh).
When you are ready to compare, here are solid answers — not the only ones, but clear and portable:
ps -p $$ -o pid,user,args
pgrep -a sleep
ps aux --sort=-%mem | head -n 11
ps -p "$(pgrep -n sleep)" -o pid,user,%mem,rss,args
pgrep -af ssh
Clean up when finished (newest sleep only — be careful on shared hosts):
kill "$(pgrep -n sleep)"
If you can work through those five comfortably, you already cover most real ps / pgrep work: identify a PID, filter by name or user, rank by memory, read full command lines, and hand off to a live monitor only when the snapshot is not enough. Query with ps and pgrep; watch with top/htop/btop when the machine is still moving under you.