78

How can I get a tree view like the one below on OSX?

vartec@some_server:~$ ps xf
PID TTY      STAT   TIME COMMAND
11519 ?        S      0:00 sshd: vartec@pts/0
11520 pts/0    Ss     0:00  \_ -bash
11528 pts/0    R+     0:00      \_ ps xf

To clarify, I'm mostly interested in the tree structure, not the extended information.

96

You can install the pstree command using either Homebrew (my personal favourite), MacPorts or Fink and you'll get a command-line, tree view of processes on your Mac.

With Homebrew installed, just run:

brew install pstree

then use it like pstree from the command line.

20

The below small perl script I've called 'treeps' that should do exactly that; works on linux (Sci Linux 6) + OSX (10.6, 10.9)

Example output:

$ ./treeps
    |_ 1        /sbin/launchd
        |_ 10       /usr/libexec/kextd
        |_ 11       /usr/sbin/DirectoryService
        |_ 12       /usr/sbin/notifyd
        |_ 118      /usr/sbin/coreaudiod
        |_ 123      /sbin/launchd
    [..]
           |_ 157      /Library/Printers/hp/hpio/HP Device [..]
           |_ 172      /Applications/Utilities/Terminal.app [..]
              |_ 174      login -pf acct
                 |_ 175      -tcsh
                    |_ 38571    su - erco
                       |_ 38574    -tcsh

Here's the code..

#!/usr/bin/perl
# treeps -- show ps(1) as process hierarchy -- v1.0 erco@seriss.com 07/08/14
my %p; # Global array of pid info
sub PrintLineage($$) {    # Print proc lineage
  my ($pid, $indent) = @_;
  printf("%s |_ %-8d %s\n", $indent, $pid, $p{$pid}{cmd}); # print
  foreach my $kpid (sort {$a<=>$b} @{ $p{$pid}{kids} } ) {  # loop thru kids
    PrintLineage($kpid, "   $indent");                       # Recurse into kids
  }
}
# MAIN
open(FD, "ps axo ppid,pid,command|");
while ( <FD> ) { # Read lines of output
  my ($ppid,$pid,$cmd) = ( $_ =~ m/(\S+)\s+(\S+)\s(.*)/ );  # parse ps(1) lines
  $p{$pid}{cmd} = $cmd;
  # $p{$pid}{kids} = (); <- this line is not needed and can cause incorrect output
  push(@{ $p{$ppid}{kids} }, $pid); # Add our pid to parent's kid
}
PrintLineage(($ARGV[0]) ? $ARGV[0] : 1, "");     # recurse to print lineage starting with specified PID or PID 1.
  • 1
    I found this answer useful in a situation where I couldn't install Brew yet (debugging Packer+vmware issues). – Amos Shapira Mar 29 '16 at 4:46
  • 1
    This is a great answer and a great starting point as well, but it would be more useful if there was a way to truncate lines, as they get really, really long in OSX and wrap inside the terminal window. Any ideas about this? – Rolf Nov 3 '16 at 16:20
  • 3
    @Rolf treeps | cut -c 1-$COLUMNS will cut the long lines off at the width of your current terminal window. (or a simple number like 100 instead of the $COLUMNS variable) – DouglasDD Nov 8 '17 at 4:54
8

I adapted Greg Ercolano's perl script to python script.

#!/usr/bin/env python2.7

import subprocess as subp
import os.path
import sys
import re
from collections import defaultdict

def psaxo():
    cmd = ['ps', 'axo', 'ppid,pid,comm']
    proc = subp.Popen(cmd, stdout=subp.PIPE)
    proc.stdout.readline()
    for line in proc.stdout:
        yield line.rstrip().split(None,2)

def hieraPrint(pidpool, pid, prefix=''):
    if os.path.exists(pidpool[pid]['cmd']):
        pname = os.path.basename(pidpool[pid]['cmd'])
    else:
        pname = pidpool[pid]['cmd']
    ppid = pidpool[pid]['ppid']
    pppid = pidpool[ppid]['ppid']
    try:
        if pidpool[pppid]['children'][-1] == ppid:
            prefix = re.sub(r'^(\s+\|.+)[\|`](\s+\|- )$', '\g<1> \g<2>', prefix)
    except IndexError:
        pass
    try:
        if pidpool[ppid]['children'][-1] == pid:
            prefix = re.sub(r'\|- $', '`- ', prefix)
    except IndexError:
        pass
    sys.stdout.write('{0}{1}({2}){3}'.format(prefix,pname,pid, os.linesep))
    if len(pidpool[pid]['children']):
        prefix = prefix.replace('-', ' ')
        for idx,spid in enumerate(pidpool[pid]['children']):
            hieraPrint(pidpool, spid, prefix+' |- ')

if __name__ == '__main__':
    pidpool = defaultdict(lambda:{"cmd":"", "children":[], 'ppid':None})
    for ppid,pid,command in psaxo():
        ppid = int(ppid)
        pid  = int(pid)
        pidpool[pid]["cmd"] = command
        pidpool[pid]['ppid'] = ppid
        pidpool[ppid]['children'].append(pid)

    hieraPrint(pidpool, 1, '')

Example output:

launchd(1)
 |- syslogd(38)
 |- UserEventAgent(39)
 |- kextd(41)
 |- fseventsd(42)
 |- thermald(44)
 |- appleeventsd(46)
...
 |- iTerm(2879)
 |   |- login(2883)
 |   |   `- -bash(2884)
 |   |       `- Python(17781)
 |   |           `- ps(17782)
 |   |- login(7091)
 |   |   `- -bash(7092)
 |   |       `- ssh(7107)
 |   `- login(7448)
 |       `- -bash(7449)
 |           `- bash(9040)
 |               `- python(9041)
 |- installd(2909)
 |- DataDetectorsDynamicData(3867)
 |- netbiosd(3990)
 |- firefox(5026)
...
0
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Paste this in your terminal to install Homebrew which will let you install pstree.

Then install pstree using this command

brew install pstree

Now you can use the pstree command in your terminal

In case the install command fails, ie.Xcode alone is not sufficient on the version of your OS, install Command Line Developer Tools by running this command before installing pstree.

xcode-select --install
  • 1
    How does this improve on or be different to the old accepted answer apple.stackexchange.com/a/11806/237 ? – Mark Dec 17 '17 at 21:25
  • I assumed there might be some changes in the current version of the MacOS or Xcode, for example I had to install Command Line Developer Tools before installing pstree. – Ethan Stykes Dec 19 '17 at 20:06
  • No no change you always needed Xcode command line tools as mentioned in all the install instructions for the 3 package managers – Mark Dec 19 '17 at 20:08
  • Oh!, hope my answer be useful to somebody somehow. – Ethan Stykes Dec 19 '17 at 20:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .