opscape

Processes and jobs

pstree

Display running processes as a tree, showing which process started which.

pstree [OPTION...] [PID | USER]

10 of 10 examples run in Debian 13.7 on 2026-10-31 · manual: pstree(1)

pstree draws the parent/child relationships that ps shows only as a PPID column. With no argument it starts at PID 1 (on a normal system, systemd or init) and shows everything below it; give a PID to see one subtree, or a user name to see the trees of that user's processes. It answers questions like "what started this process?", "what will die if I kill this service?" and "why does this container have forty workers?".

To keep the picture small, identical sibling subtrees are merged: 4*[nginx] means four nginx children with no children of their own, and threads appear in braces, {python3}. Add -p for PIDs (which also turns the merging off, since each PID is different), -a for command lines, -s to show the ancestors of a PID, and -u to mark where the user changes.

In this sandbox, PID 1 is the runner, a python3 process, with sshd and the bash -c shell of each example below it, so the trees are small. On a real machine pstree -p | less is the way to read the whole thing.

Examples

Show the whole process tree

(sleep 300 & sleep 301 & wait) &
sleep 0.2
pstree
kill %1
output
python3-+-bash-+-bash---2*[sleep]
        |      `-pstree
        |-sshd
        `-2*[{python3}]

PID 1 is the root, here the sandbox's runner. Below it are sshd and the example's shell, whose children are pstree itself and the subshell. 2*[sleep] merges the subshell's two identical sleep children, and 2*[{python3}] stands for two threads of the runner.

Show PIDs

(sleep 300 & sleep 301 & wait) &
sleep 0.2
pstree -p
kill %1
output
python3(1)-+-bash(1929)-+-bash(1930)-+-sleep(1932)
           |            |            `-sleep(1933)
           |            `-pstree(1934)
           |-sshd(8)
           |-{python3}(9)
           `-{python3}(10)

-p puts each PID in parentheses and stops merging identical subtrees, so both sleep processes get their own line. Thread IDs appear in braces.

Show the tree under one process

(sleep 300 & sleep 301 & wait) &
sleep 0.2
pstree -p $$
kill %1
output
bash(1935)-+-bash(1936)-+-sleep(1938)
           |            `-sleep(1939)
           `-pstree(1940)

Giving a PID limits the tree to that process and its descendants; $$ is the current shell, so this shows what the example started.

Show command lines

sleep 300 &
python3 -c 'import time; time.sleep(300)' &
sleep 0.2
pstree -a $$
kill %1 %2
output
bash -c...
  |-pstree -a 1941
  |-python3 -c import time; time.sleep(300)
  `-sleep 300

-a adds each process's arguments. Long command lines, like the shell's own, are cut short with ...; -l stops the truncation.

Find out what started a process

(sleep 300 & wait) &
sleep 0.2
pstree -s -p "$(pgrep -n -x sleep)"
kill %1
output
python3(1)---bash(1946)---bash(1947)---sleep(1949)

-s prints the chain of parents above the given PID, all the way to PID 1. On a server this answers "which service or login session does this process belong to?".

Show or hide threads

python3 -c 'import threading, time
for _ in range(2): threading.Thread(target=time.sleep, args=(30,)).start()' &
sleep 0.3
pstree -p $!
pstree -p -T $!
output
python3(1953)-+-{python3}(1955)
              `-{python3}(1956)
python3(1953)

Threads are listed in braces with their thread IDs. -T hides them, which makes busy servers with hundreds of threads readable.

Show where the user changes

sleep 300 &
pstree -u
kill %1
output
python3-+-bash(dev)-+-pstree
        |           `-sleep
        |-sshd
        `-2*[{python3}]

-u adds the user name in parentheses wherever a process runs as a different user from its parent: here the root-owned runner starts the bash that runs as dev. Useful for spotting privilege drops (or unexpected privilege) in daemons.

Show only one user's process trees

(sleep 300 & wait) &
sleep 0.2
pstree dev
kill %1
output
bash-+-bash---sleep
     `-pstree

A user name instead of a PID shows the trees rooted at that user's top-level processes, leaving out everything above them.

Sort children by PID

sleep 300 &
sleep 0.1
pstree -n -p 1
kill %1
output
python3(1)-+-sshd(8)
           |-{python3}(9)
           |-{python3}(10)
           `-bash(1966)-+-sleep(1967)
                        `-pstree(1969)

By default siblings are sorted by name; -n sorts them by PID, which shows them in the order they were started.

A PID that does not exist is not an error

pstree 99999
echo "exit status: $?"
output
exit status: 0

pstree prints nothing and still exits 0, so it cannot double as an existence test. Use kill -0 PID or ps -p PID for that.

Common pitfalls

  • Reading 3*[worker] as one process. It is three identical children merged; add -p (or -c) to see each one.

  • Expecting box-drawing characters in logs or pipes to look right. pstree chooses line style by terminal and locale; force plain ASCII with -A when the output goes to a file or e-mail.

  • Forgetting that orphans are re-parented. When a parent dies its children move under PID 1 (or a subreaper such as systemd --user), so the tree no longer shows who originally started them.

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).

  • pstree is from psmisc and is Linux-specific; macOS has no pstree by default (Homebrew has a different implementation with different options). FreeBSD offers it as a port. ps -ef --forest or ps axjf give a similar view on Linux without psmisc.

Options worth knowing

A selection, described in our own words. For the full list, see pstree(1) or pstree --help.

OptionWhat it does
-p, --show-pidsShow PIDs; also stops merging identical subtrees.
-a, --argumentsShow each process's command-line arguments.
-l, --longDo not truncate long lines.
-s, --show-parentsShow the ancestors of the given PID.
-u, --uid-changesShow the user name where it differs from the parent's.
-n, --numeric-sortSort siblings by PID instead of by name.
-c, --compact-notDo not merge identical subtrees.
-g, --show-pgidsShow process group IDs.
-T, --hide-threadsHide threads, show processes only.
-t, --thread-namesShow threads' own names instead of the process name.
-h, --highlight-allHighlight the current process and its ancestors.
-H, --highlight-pid PIDHighlight PID and its ancestors.
-A, --asciiDraw the tree with plain ASCII characters.
-U, --unicodeDraw the tree with Unicode line characters.
-S, --ns-changesShow where processes enter a different namespace.
-V, --versionPrint the version and exit.

Related