Processes and jobs
ps
Print a snapshot of running processes, with the columns, filters and sort order you choose.
ps [OPTION...]
ps takes one snapshot of the process table and prints it. With no options it shows only the
processes attached to your current terminal, which is rarely what you want. The two everyday
forms are ps -ef (every process, System V style) and ps aux (every process, BSD style, with
CPU and memory columns). After that, -o is the option worth learning: it picks exactly the
columns you want, and --sort orders them, which turns ps into a precise query tool for
scripts.
The procps ps on Linux accepts three option dialects at once. Options with one dash (-e,
-f, -o) are the Unix/POSIX style; options with no dash (aux, axjf) are the old BSD
style; options with two dashes (--sort, --forest) are GNU long options. They are not
interchangeable: ps -aux and ps aux mean different things, and ps a and ps -a select
different processes. In BSD style, a means "all users' processes that have a terminal", x
adds the ones without a terminal (daemons, cron jobs, anything started from a script) and u
switches to the user-oriented column set (USER, %CPU, %MEM, VSZ, RSS, STAT,
START). So aux reads as "all processes, terminal or not, in user format". Likewise ps axjf
is a+x, j for job-control columns (PPID, PGID, SID) and f for an ASCII-art forest.
The examples run inside a container, so the process list is short: the sandbox's runner (PID 1),
sshd, and the bash -c shell that runs each example, which is why the example's own command
line shows up in the listings. For a live, refreshing view use top; to find PIDs by name use
pgrep; for the parent/child tree, pstree draws it more compactly.
Examples
Show the processes started from this shell
sleep 300 &
ps
kill %1
PID TTY TIME CMD 1886 ? 00:00:00 bash 1887 ? 00:00:00 sleep 1888 ? 00:00:00 ps
Plain ps lists processes with your user ID on the same terminal as ps. The examples run
without a terminal (TTY is ?), so it shows the shell, the background sleep and ps
itself. TIME is CPU time used, not how long the process has existed. The last line
cleans up the background job.
List every process on the system
ps -ef
UID PID PPID C STIME TTY TIME CMD root 1 0 21 20:19 ? 00:00:15 python3 /opt/runner/run.py root 8 1 0 20:19 ? 00:00:00 sshd: /usr/sbin/sshd [listen dev 1889 1 0 20:20 ? 00:00:00 ps -ef
-e selects every process, -f adds the full-format columns: owner, PPID (parent PID),
C (CPU use as a lifetime percentage), start time (STIME) and the full command line. In
this container that is the root-owned runner, sshd and ps itself. A real server shows
hundreds of lines, including kernel threads in square brackets.
List every process with CPU and memory use (BSD style)
ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 21.8 0.0 252788 18160 ? Rsl 20:19 0:15 python3 /opt/ root 8 0.0 0.0 11768 3356 ? Ss 20:19 0:00 sshd: /usr/sb dev 1890 0.0 0.0 6788 3068 ? R 20:20 0:00 ps aux
No dash: these are BSD options. %CPU and %MEM are percentages, VSZ the virtual size
and RSS the resident memory, both in KiB. STAT codes: S sleeping, R running, s
session leader, + foreground on a terminal. The command column is cut at the terminal
width (80 here); add ww (ps auxww) for full command lines.
Choose exactly which columns to print
sleep 300 &
ps -o pid,ppid,user,stat,etime,args
kill $!
PID PPID USER STAT ELAPSED COMMAND 1891 1 dev S 00:00 /bin/bash -c sleep 300 & ps -o pid,ppi 1892 1891 dev S 00:00 sleep 300 1893 1891 dev R 00:00 ps -o pid,ppid,user,stat,etime,args
-o takes a comma-separated list of column names. etime is elapsed time since the process
started ([[dd-]hh:]mm:ss) and args the full command line; comm would give just the
program name. Without a selection option, -o still applies to the current terminal's
processes.
Show processes by command name
sleep 300 & sleep 600 &
ps -C sleep -o pid,etimes,args
PID ELAPSED COMMAND 1895 0 sleep 300 1896 0 sleep 600
-C NAME selects processes whose command name is exactly NAME, with no pattern matching
and no risk of matching the grep in ps | grep. etimes is elapsed time in plain
seconds, easier to compare in a script than etime.
Get a bare value for a script
sleep 300 &
ps -o pid= -o etimes= -p $!
echo "state: $(ps -o stat= -p $!)"
1898 0 state: S
A column name followed by = with nothing after it prints no header, so the output is just
the value. -p PID selects one process. The spaces before the numbers are column padding;
trim them or use $(( )) if you need a number.
Find the processes using the most memory
ps -eo pid,user,rss,comm --sort=-rss | head -5
PID USER RSS COMMAND
1 root 18164 python3
8 root 3356 sshd
1902 dev 3004 ps
1901 dev 2412 bash --sort=-rss sorts by resident memory, largest first (a leading - reverses the order;
+ or nothing is ascending). head -5 keeps the header and the top four. On a real server
this is the quickest answer to "what is eating the RAM".
Find the processes using the most CPU (BSD style)
ps aux --sort=-%cpu | head -4
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 21.9 0.0 252788 18164 ? Ssl 20:19 0:15 python3 /opt/ root 8 0.0 0.0 11768 3356 ? Ss 20:19 0:00 sshd: /usr/sb dev 1904 0.0 0.0 4488 2400 ? S 20:20 0:00 /bin/bash -c
BSD selection with a GNU long option mixed in, which procps allows. %CPU is CPU time
divided by the process's lifetime, an average since it started, not the current load; for
"right now" use top.
Show parent and child processes as a tree
(sleep 300 & sleep 400 & wait) &
sleep 0.2
ps -u dev --forest -o pid,ppid,args
kill %1
PID PPID COMMAND 1907 1 /bin/bash -c (sleep 300 & sleep 400 & wait) & sleep 0.2 ps -u de 1908 1907 \_ /bin/bash -c (sleep 300 & sleep 400 & wait) & sleep 0.2 ps - 1910 1908 | \_ sleep 300 1911 1908 | \_ sleep 400 1912 1907 \_ ps -u dev --forest -o pid,ppid,args
--forest indents children under their parent with \_. The subshell in parentheses is a
forked copy of the shell, so it shows the same command line; it is the parent of the two
sleep processes, and its wait keeps it alive. -u dev selects by effective user.
See when a process started
sleep 300 &
ps -o pid,lstart,etime,args -p $!
PID STARTED ELAPSED COMMAND 1914 Sat Oct 31 20:20:33 2026 00:00 sleep 300
lstart is the full start timestamp, etime the elapsed time since. Both are computed from
the kernel's boot-relative start time, so they are correct even if the clock was changed
after the process started.
Show the threads of a process
python3 -c 'import threading, time
for _ in range(3): threading.Thread(target=time.sleep, args=(30,), daemon=True).start()
time.sleep(30)' &
sleep 0.5
ps -L -o pid,lwp,nlwp,comm -p $!
PID LWP NLWP COMMAND 1916 1916 4 python3 1916 1918 4 python3 1916 1919 4 python3 1916 1920 4 python3
-L prints one line per thread. LWP is the thread ID and NLWP the thread count: the
main Python thread plus the three it started share one PID.
Check whether a PID is still running
ps -p 99999 -o pid,args; echo "exit status: $?"
PID COMMAND exit status: 1
When nothing matches, ps prints only the header and exits with status 1, which makes
ps -p "$pid" >/dev/null a usable liveness test. kill -0 "$pid" does the same job without
starting another program.
Common pitfalls
ps aux | grep nginxalso matches thegrepprocess itself. Usepgrep -a nginxorps -C nginx, or the old trickgrep '[n]ginx', whose own command line does not match its pattern.ps -auxis notps aux. With a dash it means-aplus-u x, processes of a user named "x". procps guesses you meantauxwhen no such user exists, but other systems (and a machine with a userx) will not. Typeps auxorps -ef.The command column is cut at the terminal width (or at
COLUMNS, which is 80 in these examples), so long Java or Python command lines lose the part you wanted. Addww(ps auxww,ps -eo pid,args ww) for unlimited width.%CPUis a lifetime average. A process that just started spinning shows a low value; usetop -b -n 1orpidstatfor current usage.Parsing the default output with
awk '{print $2}'breaks when a column is empty or the layout differs between systems. Ask for exactly what you need:ps -o pid= -C name.
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
macOS and BSD
pssupport-ef,aux,-o,-pand-u, but not the GNU long options: no--sort,--forestor--no-headers. On macOS sort with-m(memory) or-r(CPU), or pipe tosort.-C NAME(select by command name) is procps-only; on macOS,-Cmeans something unrelated. Usepgrepthere.-Lon macOS lists the column keywords-oaccepts instead of threads;ps -Mshows threads there. For portable scripts stick to POSIX column names:ps -o pid,ppid,user,etime,argsworks on both.
Options worth knowing
A selection, described in our own words. For the full list, see ps(1) or ps --help.
| Option | What it does |
|---|---|
-e | Select every process (same as -A). |
-A | Select every process (same as -e). |
-f | Full format: UID, PPID, start time and full command line. |
-F | Extra full format: adds memory size, RSS and the CPU it last ran on. |
-l | Long format: adds state, priority, nice value and wait channel. |
-o, --format COLUMNS | Print the comma-separated list of columns given; name= hides a header. |
-p, --pid PIDLIST | Select processes by PID. |
--ppid PIDLIST | Select processes whose parent is in PIDLIST. |
-C CMDLIST | Select processes by exact command name. |
-u, --user USERLIST | Select processes by effective user name or ID. |
-U, --User USERLIST | Select processes by real user name or ID. |
-g, --group GRPLIST | Select by session or effective group name. |
-t, --tty TTYLIST | Select processes attached to the given terminals. |
-s, --sid SESSLIST | Select processes in the given sessions. |
-a | Select all processes with a terminal except session leaders. |
-d | Select all processes except session leaders. |
-N, --deselect | Invert the selection. |
-H | Indent children under their parents (process hierarchy). |
--forest | Draw the process tree with ASCII art. |
--sort SPEC | Sort by columns, e.g. -rss or +pid,-etime. |
-L | Show one line per thread, with LWP and NLWP columns. |
-T | Show threads with an SPID column. |
-j | Jobs format: PGID and SID columns. |
-y | With -l, show RSS instead of flags and ADDR. |
-w | Wide output; give it twice for unlimited width. |
--no-headers | Do not print the header line. |
--headers | Repeat the header line once per page of output. |
-q, --quick-pid PIDLIST | Select by PID in quick mode, skipping some slow lookups. |
-V, --version | Print the procps version. |
Related
topShow a live, sorted view of processes and system load; batch mode prints snapshots for logs and scripts.pgrepPrint the PIDs of processes whose name (or full command line) matches a pattern, with filters by user, parent and age.pstreeDisplay running processes as a tree, showing which process started which.killSend a signal to processes by PID or job number; by default TERM, which asks a process to exit.lsofList open files and the processes holding them, including network sockets, deleted files and working directories.- Pipes and pipelinesHow cmd1 | cmd2 connects processes, which exit status a pipeline returns, PIPESTATUS, pipefail, SIGPIPE, and why variables set in a piped loop vanish.