Skip to content

ps Command Examples for Linux Process Monitoring

Updated 7 min read

Updated: 18 October 2026 · Applies to: procps-ng 4.0.4 (ps, watch) and psmisc 23.6 (pstree) on AlmaLinux 10.2, tested; Ubuntu 26.04 and Debian 13 ship the same procps-ng 4.0.4

ps ("process status") prints a snapshot of the processes running on a Linux or Unix system. ps -ef or ps aux lists them all; the options below filter that list by user, group, PID, terminal or name, show threads and process trees, choose and sort the columns, and show SELinux labels. For the basics (reading ps aux, top and htop) see How to List and Find Running Processes in Linux; to turn a PID into a name or back, see Get a Process Name From a PID in Linux.

ps -fu alice                  # processes of user alice
ps -fG web                    # processes of group web
ps -fp 97,89                  # chosen PIDs
ps -f --ppid 89               # children of PID 89
ps -C sleep                   # by command name
ps -ft pts/0                  # on one terminal
ps -ef --forest               # as a tree
ps -fL -p 97                  # threads of PID 97
ps -eo pid,user,etime,args --sort=-rss   # your own columns, sorted
ps -eZ                        # SELinux context
watch -n 2 'ps -eo pid,%cpu,args --sort=-%cpu | head'   # live view

Three option styles. According to the ps manual, ps accepts Unix options (grouped, with a dash: ps -ef), BSD options (grouped, without a dash: ps aux) and GNU long options (two dashes: --sort). That is why both ps -ef and ps aux work.

The output below is a lab example from an AlmaLinux 10.2 test container with systemd as process 1, user alice (UID 1000) and user deploy (UID 1001, member of group web). A real server lists many more processes.

1. Processes of one user

$ ps -fu 1001
UID          PID    PPID  C STIME TTY          TIME CMD
deploy        97      90  0 09:34 ?        00:00:00 python3 /usr/local/bin/worker.py
deploy       100      88  0 09:34 ?        00:00:00 sleep 1002

A user name works too (ps -fu deploy). -u selects by effective user, -U by real user. They differ for setuid programs. Here alice started a setuid copy of sleep, which runs with root rights:

$ ps -o pid,ruser,euser,comm -U alice
    PID RUSER    EUSER    COMMAND
    103 alice    root     suidsleep
    104 alice    alice    sleep
$ ps -o pid,ruser,euser,comm -u alice
    PID RUSER    EUSER    COMMAND
    104 alice    alice    sleep

According to the ps manual, selection options add up, so ps -U root -u root lists every process whose real or effective user is root.

2. Processes of one group

$ ps -o pid,user,rgroup,egroup,comm -G web
    PID USER     RGROUP   EGROUP   COMMAND
    100 deploy   web      web      sleep

-G selects by real group. -g selects by session or effective group name; ps -fg web found the same process. ps -eo pid,user,group,comm --sort=user lists every process with its user and group.

3. By PID, parent PID or name

$ ps -fp 97,89
UID          PID    PPID  C STIME TTY          TIME CMD
root          89       1  0 09:34 ?        00:00:00 bash -c sleep 1003 & sleep 1004 & wait
deploy        97      90  0 09:34 ?        00:00:00 python3 /usr/local/bin/worker.py
$ ps -f --ppid 89
UID          PID    PPID  C STIME TTY          TIME CMD
root          98      89  0 09:34 ?        00:00:00 sleep 1003
root          99      89  0 09:34 ?        00:00:00 sleep 1004
$ ps -C sleep,python3 -o pid,user,etime,args | head -4
    PID USER         ELAPSED COMMAND
     91 root           00:06 sleep 1005
     94 root           00:06 sleep 900
     96 root           00:06 [sleep] <defunct>

-C matches the exact program name. ps -C sleep -o pid= prints only the PIDs, one per line, which is handy in scripts. ps -p PID returns exit code 1 when the process does not exist (tested with a PID that was not in use).

4. By terminal

$ ps -o pid,tty,stat,args -t pts/0
    PID TT       STAT COMMAND
    102 pts/0    Ss+  sleep 1006

Run tty to see the name of your own terminal. A ? in the TTY column means the process has no terminal, which is normal for services.

5. Process tree

$ ps -ef --forest
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 09:33 ?        00:00:00 /sbin/init
root          12       1  0 09:33 ?        00:00:00 /usr/lib/systemd/systemd-journald
root          89       1  0 09:34 ?        00:00:00 bash -c sleep 1003 & sleep 1004 & wait
root          98      89  0 09:34 ?        00:00:00  \_ sleep 1003
root          99      89  0 09:34 ?        00:00:00  \_ sleep 1004
root          90       1  0 09:34 ?        00:00:00 runuser -u deploy -- python3 /usr/local/bin/worker.py
deploy        97      90  0 09:34 ?        00:00:00  \_ python3 /usr/local/bin/worker.py
(shortened)

ps axjf is the BSD-style tree with process group and session IDs. pstree -p (package psmisc) draws a compact tree, for the whole system or from one PID, and shows threads in curly brackets:

$ pstree -p 89
bash(89)-+-sleep(98)
         `-sleep(99)
$ pstree -p
systemd(1)-+-bash(89)-+-sleep(98)
           |          `-sleep(99)
(shortened)
           |-runuser(90)---python3(97)-+-{python3}(105)
           |                           |-{python3}(106)
           |                           `-{python3}(107)

6. Threads

$ ps -fL -p 97
UID          PID    PPID     LWP  C NLWP STIME TTY          TIME CMD
deploy        97      90      97  0    4 09:34 ?        00:00:00 python3 /usr/local/bin/worker.py
deploy        97      90     105  0    4 09:34 ?        00:00:00 python3 /usr/local/bin/worker.py
deploy        97      90     106  0    4 09:34 ?        00:00:00 python3 /usr/local/bin/worker.py
deploy        97      90     107  0    4 09:34 ?        00:00:00 python3 /usr/local/bin/worker.py

LWP is the thread ID and NLWP the number of threads. ps -T -p 97 shows the same with an SPID column, and ps -o pid,nlwp,args -p 97 just the count. ps -eLf --no-headers | wc -l counts all threads on the system (29 in our container).

7. Choose your own columns with -o

$ ps -o pid,etime=RUNNING_FOR,args -p 97
    PID RUNNING_FOR COMMAND
     97       00:06 python3 /usr/local/bin/worker.py
$ ps -p 97 -o pid,lstart,etime
    PID                  STARTED     ELAPSED
     97 Mon Oct 12 09:34:46 2026       00:06

A name after = renames the header; a bare = removes it. Useful columns: pid, ppid, user, group, stat, %cpu, %mem, rss (physical memory in kilobytes), etime (running time), lstart (start time), nlwp, tty, comm (name) and args (full command). ps L lists every column name (190 lines on procps-ng 4.0.4). More on running time in How to Check Execution Time of a Process in Linux.

8. Sort the output

$ ps -eo pid,ppid,user,etime,%cpu,%mem,rss,args --sort=-rss | head -3
    PID    PPID USER         ELAPSED %CPU %MEM   RSS COMMAND
      1       0 root           00:59  0.1  0.2 11520 /sbin/init
     97      90 deploy         00:06  0.1  0.2  9088 python3 /usr/local/bin/worker.py

A minus sign sorts from high to low; several keys are separated by commas, for example --sort=-%cpu,-%mem. --sort=etime puts the newest processes first. For finding heavy processes, see Find Top Running Processes by Highest Memory and CPU Usage in Linux.

9. Process states and zombies

$ ps -e -o stat= | cut -c1 | sort | uniq -c
      1 R
     26 S
      1 Z
$ ps -eo pid,ppid,stat,args | awk '$3 ~ /^Z/'
     96      91 Z    [sleep] <defunct>

According to the ps manual, R is running or runnable, S sleeping, D uninterruptible sleep (usually disk or network I/O), T stopped and Z a zombie: a process that has ended but has not been reaped by its parent. A zombie goes away when its parent reaps it or exits, so look at the parent (PPID 91 here). Extra letters: s session leader, l multi-threaded, + foreground, < high and N low priority. Processes that stay in D are waiting for I/O, for example a slow disk or network file system.

10. SELinux context

ps -eZ (also -M or --context) adds a LABEL column, and ps -eo label,pid,comm shows it with your own columns. According to Red Hat's SELinux guide, the Apache web server runs as system_u:system_r:httpd_t:s0; the third field (httpd_t) is the domain SELinux uses to confine it. Inside our test container, where SELinux is not visible, every process showed only kernel, so run this on the host itself. More in Understanding SELinux File Labelling and SELinux Context.

11. The status of one process

The kernel keeps a readable status file for every process:

$ grep -E '^(Name|State|Pid|PPid|Uid|Threads|VmRSS)' /proc/97/status
Name:	python3
State:	S (sleeping)
Pid:	97
PPid:	90
Uid:	1001	1001	1001	1001
VmRSS:	    9088 kB
Threads:	4

According to the kernel documentation, the four Uid values are the real, effective, saved set and file system user IDs; for alice's setuid process they were 1000 0 0 0. For the status of a service rather than a process, use systemctl status nginx; see How to List Services and Check Their Status with systemctl.

12. Monitor processes in real time

ps shows a snapshot. To repeat it, wrap it in watch; press Ctrl+C to stop:

watch -n 2 'ps -eo pid,user,%cpu,%mem,args --sort=-%cpu | head -15'

According to the watch manual, the default interval is 2 seconds and -d highlights what changed between updates. For an interactive view, use top or htop.

List processes in Bash

  • jobs -l lists the background jobs of your current shell with their PIDs, for example [1]- 168 Running sleep 100 &.
  • ps -ef | grep sleep also matches the grep command itself. Use ps -ef | grep [s]leep or pgrep -a sleep, which prints PID and command line.
  • In scripts, prefer ps -C name -o pid= or pgrep over parsing the full listing.

To stop a process you found, see How to Find and Kill Running Processes in Linux.

Official documentation: ps manual (procps-ng).

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Unmanaged dedicated servers

full root access and free IPMI KVM, with Free Basic Managed Support.

Linux server management

hardening, patching, monitoring and automation for Ubuntu, Debian, RHEL and AlmaLinux.

Was this answer helpful?

Still stuck? Open a ticket