Mac OS X equivalent of the Ubuntu "tree" command

330

92

Is there an equivalent to the Ubuntu tree command for Mac OS X?

Misha Moroshko

Posted 2011-11-21T10:38:01.130

Reputation: 5 573

Answers

460

You can get the tree command on macOS, too. If you have Homebrew, all you need to do is run:

brew install tree

Read on for details.


With a package manager

There are several package managers for macOS. The most popular are: Homebrew, MacPorts, or Fink. You can install either one, but I recommend Homebrew. Do not install more than one of these at the same time!

Follow the instructions on the website, then run one of the following commands, depending on which package manager you chose.

For Homebrew:

brew install tree

For MacPorts:

sudo port install tree

For Fink:

fink install tree

The package managers offer other command line programs, including the GNU/Linux ones that do not come with macOS by default.

Installing from source

First, you have to install the Xcode command line tools by running xcode-select --install.

Then, download the tree source. Then change the Makefile to get it to work, which is also explained in @apuche's answer below. Commenting out the Linux options and uncommenting the macOS options should be enough.

Then, run ./configure, then make.

Now you have to move the tree binary file to a location that's in your executable path. For example:

sudo mkdir -p /usr/local/bin
sudo cp tree /usr/local/bin/tree

Now edit your ~/.bash_profile to include:

export PATH="/usr/local/bin:$PATH"

Reload the shell, and now which tree should point to /usr/local/bin/tree.

slhck

Posted 2011-11-21T10:38:01.130

Reputation: 182 472

"Problematic" how? – David Moles – 2015-01-21T17:54:52.803

1

@DavidMoles Because simply running make on OS X doesn't work. First, you have to know how to install the Xcode command-line tools (or generally, have some idea about building software) and then you'll find that it errors out on an undefined symbol. So you have to do some adjustments to the makefile (as explained here). Too much hassle IMO.

– slhck – 2015-01-21T22:04:02.900

+1 for clarifying. :) (The Makefile edit is also documented in this answer below, btw.)

– David Moles – 2015-01-22T17:38:46.170

>

  • Okay, you do have to install the Xcode Command Line Tools in order to compile programs that you want to install from source on OS X, but because the whole discussion is about a command line tool, namely tree, I would guess that most people have already done that, or can do that very simply. Personally, I hate package managers, so I try to install from source whenever I can. It doesn’t require any more effort to install the Xcode Command Line Tools than it does to install a package manager. Finally, suggesting that people need a package manager to install a simple little program like...
  • < – 7stud – 2015-04-09T02:32:23.673

    tree is overkill. 2) In Yosemite 10.10.2, make does not error out--it gives a warning, which I just ignored, and the tree command installed just fine. But, the source code can be easily modified to get rid of the warning. See

    comments in the other answer. 3) When you download anything that you want to install, the first step is to read the README file, then the INSTALL file. The INSTALL file for tree asks you to uncomment certain lines in the Makefile depending on what OS you are using. Someone went to a lot of trouble to make that extremely easy. It certainly isn't problematic. – 7stud – 2015-04-09T02:32:42.337

    3@7stud Many people know a few command line tools for very simple CLI tasks, and they may not know how to compile software. People sometimes struggle to understand what ./configure and make exactly do and why those are needed in the first place. Or they don't want to deal with it. Or read any help files, for that matter. They'd rather do something like apt-get install. It's fine if you prefer installations from source (and I personally do, too), but you have to accept that there are solutions that are perceived easier by others, or perhaps even the majority of normal computer users. – slhck – 2015-04-09T06:56:23.637

    @7stud I amended my answer to include more info for both ways of installing tree. – slhck – 2015-04-09T07:06:55.687

    1People sometimes struggle to understand what ./configure and make exactly do and why those are needed in the first place I've been installing software from source for 15 years, and I have no idea what ./configure and make do. I just know they are steps I need to perform in order to install software. I blindly read the README and INSTALL files, and I do whatever it says. – 7stud – 2015-04-09T17:08:58.603

    This worked, but I had to also do this in order for the link to take effect.

    – aliteralmind – 2015-11-18T17:38:26.117

    Can you get the tree command to ignore certain file types e.g. *.json? – Dhruv Ghulati – 2016-08-03T17:51:17.473

    1@DhruvGhulati Not that I know of, but you could inverse-grep it. Like tree | grep -v 'json' or similar. – slhck – 2016-08-04T08:20:37.663

    @DhruvGhulati tree --help will list all the options, one of which is -P pattern, which lists only those files that match the pattern, and another is -I pattern which omits the files that match the pattern. So tree -I '*.json' should do what you want. (Btw: I don't know what the pattern syntax is, but I found that this one worked: don't omit the single quotes.) – Steve Powell – 2017-02-28T10:33:47.280

    I installed teee from brew and the file /usr/local/bin/tree do exist, but when I type tree the system say -bash: tree: command not found. What is the problem? Thanks in advance. – Evan Hu – 2019-01-07T03:15:02.343

    @EvanHu When you run echo $PATH, is the /usr/local/bin path in there? Make sure this directory is part of your PATH and that you haven't overwritten it. Also make sure that the tree file is executable. In case of problems please ask a new question. – slhck – 2019-01-07T09:49:42.780

    http://shaunchapmanblog.com/post/329270449/how-to-install-the-tree-command-on-mac-os-x also seems to have detailed instructions but may cause issues with llvm-gcc living under /Developer if you are running Xcode 4.x; a bit of fiddling around should do the trick. – Ahmed Masud – 2011-11-21T11:04:02.027

    @MishaMoroshko Glad it worked. You'll find many programs on Homebrew, so if you ever miss something you had on Ubuntu or thought only Linux can have, Homebrew should help you! – slhck – 2011-11-21T22:15:05.307

    36

    Not exactly the same, but one quick way on the Mac is:

    find .
    

    and that's it. It will list all file paths in the current directory as a list.

    nonopolarity

    Posted 2011-11-21T10:38:01.130

    Reputation: 7 932

    If interested in a particular directory: find ./<dir_name> – raspacorp – 2016-07-08T22:12:13.817

    If only interested in files, find . -type f – Jared Beck – 2017-03-16T17:54:49.027

    3I was only interested in going a few levels deep to show the directory structure so find . -type d -maxdepth 2 worked for me – Matthew Lock – 2017-04-21T07:13:12.937

    Better use find * if you don't want to see hidden files and directories. tree doesn't show hidden files and directories by default. – asmaier – 2018-05-31T14:36:33.953

    find is a 万金油 tool. – Evan Hu – 2019-01-07T03:15:52.880

    22

    Or if your administrator won't let you install any of the brew, fink, port tools you can always build it from the source :

    curl -O ftp://mama.indstate.edu/linux/tree/tree-1.5.3.tgz
    tar xzvf tree-1.5.3.tgz
    cd tree-1.5.3/
    ls -al
    

    Edit the Makefile to comment linux part and uncomment osx area:

    # Linux defaults:
    #CFLAGS=-ggdb -Wall -DLINUX -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
    #CFLAGS=-O2 -Wall -fomit-frame-pointer -DLINUX -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
    #LDFLAGS=-s
    
    # Uncomment for OS X:
    CC=cc
    CFLAGS=-O2 -Wall -fomit-frame-pointer -no-cpp-precomp
    LDFLAGS=
    XOBJS=strverscmp.o
    

    Optional: Forcing color output

    And while you're at it, if you want to force tree to always colorize the output, you can always edit the main method of the tree.c file and add force_color=TRUE; before setLocale(LC_TYPE,"");

    Finally hit make and you're done building tree for mac.

    Tribute goes to Shaun Chapman for his original post on his blog.

    apouche

    Posted 2011-11-21T10:38:01.130

    Reputation: 321

    Great answer. Can you add a note on how to move it to /bin (or some path so that it can be used globally)? – Khanh Nguyen – 2014-10-10T04:57:45.463

    FYI, compiling 1.7.0 under Yosemite I got: warning: format specifies type 'long' but the argument has type 'long long'. The fix was to change a format specifier from %9ld to %9lld. – David Moles – 2015-01-21T18:02:38.667

    @KhanhNguyen -- Personally, I put stuff like this in ~/bin, and have a line export PATH=~/bin:$PATH in my ~/.bash_profile. – David Moles – 2015-01-21T18:03:34.567

    @DavidMoles, Same warning here. I ignored it, and sudo make install seemed to work. However, for the recored where is that format specifier? It's not in the Makefile. Ah, I found it in tree.c. – 7stud – 2015-04-09T01:42:54.913

    It's not setLocale, it's setlocale() so you will need to search for the correct term. Installing from source is the way to go. The Install file tells you which lines to uncomment in the Makefile depending on your OS, so it couldn't be easer (you don't have to comment out the Linux options). However, this answer has too many errors. The colorizing seems random to me, so I would just skip it. – 7stud – 2015-04-09T01:55:35.960

    Couldn't get to Shaun's website; thanks for the heads up on modifying the Makefile. – Paul Nathan – 2012-10-26T14:27:31.737

    Specifically, you can add force_color = TRUE;. No semicolon and you get a compile error. – tgrosinger – 2013-09-06T15:55:55.063

    1I've just built version 1.7 and instead of setLocale its setlocale. So in tree.c, you look for setlocale(LC_TYPE,""); and thanks! – Avi Cohen – 2014-05-02T09:49:23.780

    21

    You should probably be using homebrew. If you do:

    brew install tree
    

    nichochar

    Posted 2011-11-21T10:38:01.130

    Reputation: 339

    18

    There isn’t a formal tree command per se however you can do this:

    Save the following script to /usr/local/bin/tree

    #!/bin/bash
    
    SEDMAGIC='s;[^/]*/;|____;g;s;____|; |;g'
    
    if [ "$#" -gt 0 ] ; then
       dirlist="$@"
    else
       dirlist="."
    fi
    
    for x in $dirlist; do
         find "$x" -print | sed -e "$SEDMAGIC"
    done
    

    Change the permissions so you can run it:

    chmod 755 /usr/local/bin/tree 
    

    Of course you may have to create /usr/local/bin:

    sudo mkdir -p /usr/local/bin/tree 
    

    Ahmed Masud

    Posted 2011-11-21T10:38:01.130

    Reputation: 424

    Any idea how to color code the directories to a different color? Or reuse your directory listing colors? – Jen S. – 2014-09-23T05:46:37.187

    1@JenS. of course you can simply change the find command to deal with that – Ahmed Masud – 2014-09-24T20:41:35.253

    It misses all the options of tree, but still a nice little solution. – slhck – 2011-11-21T11:01:26.140

    @slhck hehe it was a quick hack solution... – Ahmed Masud – 2011-11-21T11:05:40.213

    You might want to quote your variables though. – slhck – 2011-11-21T11:12:58.180

    $x should be $dirlist shouldn't be quoted... because of the special expansion of "$@" – Ahmed Masud – 2011-11-21T11:24:23.733

    @AhmedMasud I referenced this over here: http://superuser.com/questions/532156/how-do-i-print-a-tree-with-files-in-bash-for-windows#comment643537_532156 if you answer there I'll give you the marked answer

    – jcollum – 2013-01-10T23:10:01.203

    6

    An alternative using find and awk:

    #!/bin/bash
    find . -print 2>/dev/null | awk '!/\.$/ { \
        for (i=1; i<NF; i++) { \
            printf("%4s", "|") \
        } \
        print "-- "$NF \
    }' FS='/'
    

    jweyrich

    Posted 2011-11-21T10:38:01.130

    Reputation: 1 106

    4

    I found a simple solution here: http://murphymac.com/tree-command-for-mac/

    So adding the following to your .bashrc, .bash_profile or any other place will make it work:

    alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"
    

    Now adding a tree command will print like this:

    # ~/my-html-app [13:03:45]$ tree
    .
    |____app.js
    |____css
    | |____main.css
    | |____theme.css
    |____index.html
    

    Shashank Agrawal

    Posted 2011-11-21T10:38:01.130

    Reputation: 143

    3

    Adding a small point to @apuche's answer for OSX El Capitan rootless feature. make install fails since we are not allowed to write into /usr/bin directory.

    vikas@MBP:~/Downloads/tree-1.7.0$ sudo make install
    Password:
    install -d /usr/bin
    install: chmod 755 /usr/bin: Operation not permitted
    install -d /usr/share/man/man1
    if [ -e tree ]; then \
            install tree /usr/bin/tree; \
        fi
    install: /usr/bin/tree: Operation not permitted
    make: *** [install] Error 71
    vikas@MBP:~/Downloads/tree-1.7.0$
    

    To overcome this, just edit Makefile to have prefix = /usr/local

    vikas027

    Posted 2011-11-21T10:38:01.130

    Reputation: 141

    Well, this technically works. But it’s invasive. So you could probably run ./configure --prefix=/usr/local before running make and make install and it would achieve the same results. – JakeGould – 2016-01-12T03:23:51.007

    2

    @JakeGould Absolutely, I do use prefix in such scenarios. But there is no configure file in the latest version of tree (1.7.0) now. The INSTALL file in the unzipped directory just says to use make and make install straightaway.

    – vikas027 – 2016-01-12T03:29:21.230

    2

    I added the following to ~/.bash_profile for use in Terminal.app. Some comments are included to help remember how find is being used.

    ##########
    ## tree ##
    ##########
    ## example ...
    #|____Cycles
    #| |____.DS_Store
    #| |____CyclesCards.json
    #| |____Carbon
    #| | |____Carbon.json
    # alternate: alias tree='find . -print | sed -e "s;[^/]*/;|____;g;s;____|; |;g"'
    # use$ tree ; tree . ; tree [some-folder-path]
    function tree {
        find ${1:-.} -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'
    }
    

    example for the current directory

    $> tree
    

    example for some path

    $> tree /some/path
    

    l --marc l

    Posted 2011-11-21T10:38:01.130

    Reputation: 307

    2

    Here is a Ruby script solution that produces a nice Unicode tree along with useful metadata.

    #!/usr/bin/env ruby
    def tree_hierarchy( root, &children )
      queue = [[root,"",true]]
      [].tap do |results|
        until queue.empty?
          item,indent,last = queue.pop
          kids = children[item]
          extra = indent.empty? ? '' : last ? '└╴' : '├╴'
          results << [ indent+extra, item ]
          results << [ indent, nil ] if last and kids.empty?
          indent += last ? '  ' : '│ '
          parts = kids.map{ |k| [k,indent,false] }.reverse
          parts.first[2] = true unless parts.empty?
          queue.concat parts
        end
      end
    end
    def tree(dir)
      cols = tree_hierarchy(File.expand_path(dir)) do |d|
        File.directory?(d) ? Dir.chdir(d){ Dir['*'].map(&File.method(:expand_path)) } : []
      end.map do |indent,path|
        if path
          file = File.basename(path) + File.directory?(path) ? '/' : ''
          meta = `ls -lhd "#{path}"`.split(/\s+/)
          [ [indent,file].join, meta[0], meta[4], "%s %-2s %s" % meta[5..7] ]
        else
          [indent]
        end
      end
      maxs = cols.first.zip(*(cols[1..-1])).map{ |c| c.compact.map(&:length).max }
      tmpl = maxs.map.with_index{ |n,i| "%#{'-' if cols[0][i][/^\D/]}#{n}s" }.join('  ')
      cols.map{ |a| a.length==1 ? a.first : tmpl % a }
    end
    puts tree(ARGV.first || ".") if __FILE__==$0
    

    You could modify the meta = … line to extract different metadata to display, hand-picking out the split pieces on the next line. With a little more work you could pass arbitrary ls arguments to select the metadata to show.

    Sample output (looks nicer in the OS X terminal than the font on Stack Overflow):

    phrogz$ tree UCC_IVI/
    UCC_IVI/                               drwxr-xr-x  510B  Nov 20 11:07
      ├╴docs/                              drwxr-xr-x  102B  Nov 20 19:21
      │ └╴CANMessages.txt                  -rwxr-xr-x  2.2K  Nov 20 19:21
      │ 
      ├╴effects/                           drwxr-xr-x  204B  Nov 19 17:19
      │ ├╴Depth Of Field HQ Blur.effect    -rwxr-xr-x  2.4K  Nov 19 17:19
      │ ├╴FXAA.effect                      -rwxr-xr-x  1.6K  Nov 17 15:38
      │ ├╴HDRBloomTonemap.effect           -rwxr-xr-x   11K  Nov 17 15:38
      │ └╴SMAA1X.effect                    -rwxr-xr-x  4.4K  Nov 19 17:19
      │ 
      ├╴fonts/                             drwxr-xr-x  136B  Nov 17 15:38
      │ ├╴Arimo-Regular.ttf                -rwxr-xr-x   43K  Nov 17 15:38
      │ └╴OFL.txt                          -rwxr-xr-x  4.3K  Nov 17 15:38
      │ 
      ├╴maps/                              drwxr-xr-x  238B  Nov 19 17:19
      │ ├╴alpha-maps/                      drwxr-xr-x  136B  Nov 17 15:38
      │ │ ├╴rounded-boxes-3.png            -rwxr-xr-x  3.6K  Nov 17 15:38
      │ │ └╴splatter-1.png                 -rwxr-xr-x   35K  Nov 17 15:38
      │ │ 
      │ ├╴effects/                         drwxr-xr-x  136B  Nov 19 17:19
      │ │ ├╴AreaTex-yflipped.dds           -rwxr-xr-x  175K  Nov 19 17:19
      │ │ └╴SearchTex-yflipped.png         -rwxr-xr-x  180B  Nov 19 17:19
      │ │ 
      │ ├╴IBL/                             drwxr-xr-x  136B  Nov 17 15:38
      │ │ ├╴028-hangar.hdr                 -rwxr-xr-x  1.5M  Nov 17 15:38
      │ │ └╴FieldAirport.hdr               -rwxr-xr-x  1.5M  Nov 17 15:38
      │ │ 
      │ ├╴icons/                           drwxr-xr-x  238B  Nov 19 17:19
      │ │ ├╴icon_climate.dds               -rwxr-xr-x  683K  Nov 19 17:19
      │ │ ├╴icon_music.dds                 -rwxr-xr-x  683K  Nov 19 17:19
      │ │ ├╴icon_navigation.dds            -rwxr-xr-x  683K  Nov 19 17:19
      │ │ ├╴icon_phone.dds                 -rwxr-xr-x  683K  Nov 19 17:19
      │ │ └╴icon_surroundView.dds          -rwxr-xr-x  683K  Nov 19 17:19
      │ │ 
      │ └╴materials/                       drwxr-xr-x  102B  Nov 19 17:19
      │   └╴spherical_checker.png          -rwxr-xr-x   11K  Nov 19 17:19
      │   
      ├╴materials/                         drwxr-xr-x  102B  Nov 19 17:19
      │ └╴thin_glass_refractive.material   -rwxr-xr-x  6.0K  Nov 19 17:19
      │ 
      ├╴models/                            drwxr-xr-x  136B  Nov 19 17:19
      │ ├╴BokehParticle/                   drwxr-xr-x  136B  Nov 19 17:19
      │ │ ├╴BokehParticle.import           -rwxr-xr-x  739B  Nov 19 17:19
      │ │ └╴meshes/                        drwxr-xr-x  102B  Nov 19 17:19
      │ │   └╴Mesh.mesh                    -rwxr-xr-x  1.1K  Nov 19 17:19
      │ │   
      │ └╴Glass_Button/                    drwxr-xr-x  136B  Nov 19 17:19
      │   ├╴Glass_Button.import            -rwxr-xr-x  1.2K  Nov 19 17:19
      │   └╴meshes/                        drwxr-xr-x  136B  Nov 19 17:19
      │     ├╴GlassButton.mesh             -rwxr-xr-x   44K  Nov 19 17:19
      │     └╴Icon.mesh                    -rwxr-xr-x  1.8K  Nov 19 17:19
      │     
      ├╴scripts/                           drwxr-xr-x  204B  Nov 19 17:19
      │ ├╴App.lua                          -rwxr-xr-x  764B  Nov 17 15:38
      │ ├╴CANSim.lua                       -rwxr-xr-x   29K  Nov 17 15:38
      │ ├╴ObjectWiggler.lua                -rwxr-xr-x  3.7K  Nov 19 17:19
      │ └╴PathWiggler.lua                  -rwxr-xr-x  2.9K  Nov 17 15:38
      │ 
      ├╴states/                            drwxr-xr-x  170B  Nov 19 18:45
      │ ├╴app-camera.scxml                 -rwxr-xr-x  2.4K  Nov 20 11:07
      │ ├╴app-navigation.scxml             -rwxr-xr-x  590B  Nov 19 18:32
      │ └╴logic.scxml                      -rwxr-xr-x  4.2K  Nov 19 18:59
      │ 
      ├╴tests/                             drwxr-xr-x  102B  Nov 17 15:38
      │ └╴interface-navigation.scxml-test  -rwxr-xr-x   83B  Nov 17 15:38
      │ 
      ├╴UCC_IVI.uia                        -rwxr-xr-x  630B  Nov 19 17:32
      ├╴UCC_IVI.uia-user                   -rwxr-xr-x  832B  Nov 20 17:22
      ├╴UCC_IVI.uip                        -rwxr-xr-x  1.5K  Nov 17 15:38
      └╴UCC_Menu.uip                       -rwxr-xr-x   33K  Nov 19 17:19
    

    Phrogz

    Posted 2011-11-21T10:38:01.130

    Reputation: 850

    2Thanks very much for the lightweight solution! On OSX 10.9.5 (running stock Ruby 2.0.0), due to a 'no implicit conversion of true into String (TypeError)' error, I had to change the sixth line of the #tree method to read file = File.basename(path) + (File.directory?(path) ? '/' : '') – joel.neely – 2016-07-16T13:33:25.457

    1

    1. Install Xcode

    2. Get Command Line Tools

    xcode-select --install
    
    1. Install Homebrew
    ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    
    1. Install tree
    brew install tree
    

    KunMing Xie

    Posted 2011-11-21T10:38:01.130

    Reputation: 111

    1Already mentioned in two previous answers in 2011 and 2016. Do we need a third answer saying the same? – Jason S – 2017-12-12T00:24:34.927

    1

    It's not as pretty as gnu tree ... but it's real easy to alias in bash ... You can even add a little color by tacking the G option on to osx's ls color.

    alias tree='find . -type d | ls -lARG'
    

    Eddie B

    Posted 2011-11-21T10:38:01.130

    Reputation: 909

    0

    Late to the game, but I had the same question. Due to workplace restrictions, I couldn't install a package from source or via a third-party package manager.

    This is my implementation:

    # Faux tree command in OS X                                      
    
    #####################################################################
    # tree
    # Recursive directory/file listing of present working directory 
    #
    # tree /Users/foo/foo_dir
    # Recursive directory/file listing of named directory, e.g foo_dir
    #
    # tree /System/Library/ 2
    # Recursive directory/file listing of named directory, 
    # with-user defined depth of recursion, e.g. 2 
    #####################################################################
    
    tree ()
    {
        [ -n "$2" ] && local depth="-maxdepth $2";
        find "${1:-.}" ${depth} -print 2> /dev/null | sed -e 's;[^/]*/;|____;g;s;____|; |;g'
    }
    

    Simply add the function to /Users/foo/.profile or .bash_profile, then refresh the profile with: source .profile or: source .bash_profile

    marshki

    Posted 2011-11-21T10:38:01.130

    Reputation: 146