Files and directories
tree
Draw a directory and everything below it as an indented tree.
tree [OPTION...] [DIRECTORY...]
tree prints a directory hierarchy with line-drawing characters, followed by a count of
directories and files. It is the fastest way to understand the layout of an unfamiliar project
or to paste a structure into documentation.
It is not part of coreutils, so it may need installing (apt install tree, brew install tree).
Like ls, it hides dotfiles unless you pass -a. The useful options limit depth (-L),
filter by pattern (-P, -I), and add details (-h for sizes, -p for permissions).
For machine-readable output, tree -J prints JSON; for anything scripted, find is still the
better tool.
Examples
Show a directory tree
tree src
src ├── Makefile ├── app.py ├── lib │ └── helpers.py ├── main.c └── util.sh 2 directories, 5 files
Subdirectories are expanded in place. The summary counts the starting directory too, so
src and lib make "2 directories".
Limit the depth
tree -L 1
. ├── README.md ├── access.log ├── data ├── file with spaces.txt ├── link-to-notes -> notes.txt ├── logs ├── notes.txt ├── photos ├── scripts ├── src └── todo.txt 6 directories, 6 files
-L 1 shows only the top level. Without it, tree . on a real project can scroll for
thousands of lines. link-to-notes is drawn with its target and counted as a file.
Only directories
tree -d
.
├── data
├── logs
├── photos
├── scripts
└── src
└── lib
7 directories -d drops files and shows the directory skeleton.
Include hidden files
tree -a -L 1 | head -5
. ├── .env ├── README.md ├── access.log ├── data
-a shows names that start with a dot, such as .env, which plain tree hides. head
keeps the first five lines.
Show sizes
tree -h photos
[ 5] photos ├── [ 583] IMG_2041.png ├── [1.5K] beach.png └── [2.3K] forest.png 1 directory, 3 files
-h prints each size with a unit, like ls -lh; files under 1 KiB stay in bytes. The
size shown for the directory itself is what the filesystem reports for it, not the total of
its contents; --du would add that up.
Only files matching a pattern
tree -P '*.py' --prune
.
└── src
├── app.py
└── lib
└── helpers.py
3 directories, 2 files -P keeps files matching the wildcard (directories are always walked), and --prune
removes directories left empty by the filter, so only the path to each Python file remains.
Hide files matching a pattern
tree -I 'photos|logs|data'
. ├── README.md ├── access.log ├── file with spaces.txt ├── link-to-notes -> notes.txt ├── notes.txt ├── scripts │ ├── backup.sh │ └── greet.sh ├── src │ ├── Makefile │ ├── app.py │ ├── lib │ │ └── helpers.py │ ├── main.c │ └── util.sh └── todo.txt 4 directories, 13 files
-I excludes names matching the pattern; | separates alternatives. On a real project,
tree -I 'node_modules|.git' is the usual form.
Full paths, no indentation lines
tree -fi src
src src/Makefile src/app.py src/lib src/lib/helpers.py src/main.c src/util.sh 2 directories, 5 files
-f prints each entry's path from the starting directory, and -i removes the drawing.
The result is close to what find prints, in sorted order.
Permissions and owners
tree -pu scripts
[drwxrwxr-x dev ] scripts ├── [-rwxrwxr-x dev ] backup.sh └── [-rwxrwxr-x dev ] greet.sh 1 directory, 2 files
-p adds the permission string, -u the owner. Executable scripts show their x bits.
JSON output
tree -J src/lib
[
{"type":"directory","name":"src/lib","contents":[
{"type":"file","name":"helpers.py"}
]}
,
{"type":"report","directories":1,"files":1}
] -J writes the tree as JSON, ready for jq. The last element is the summary report.
Plain ASCII drawing
tree --charset=ascii -L 1 logs
logs |-- app.log |-- app.log.1 `-- error.log 1 directory, 3 files
--charset=ascii draws with |-- and `-- instead of box-drawing characters, safe for
e-mails and old terminals.
Common pitfalls
treewithout-Lon a large directory (a home directory,node_modules) produces a flood of output; always start with-L 2.-Ppatterns apply to files only, and the|alternation needs quoting so the shell does not treat it as a pipe.
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).
treeis a separate program on every platform, the same code on Linux and macOS; it is usually not installed by default.
Options worth knowing
A selection, described in our own words. For the full list, see tree(1) or tree --help.
| Option | What it does |
|---|---|
-a | Show hidden files too. |
-d | List directories only. |
-L LEVEL | Descend at most LEVEL directories deep. |
-f | Print the full path prefix for each entry. |
-i | Do not print the indentation lines. |
-P PATTERN | List only files matching the wildcard PATTERN. |
-I PATTERN | Do not list files matching PATTERN. |
--prune | Remove empty directories from the output. |
-h | Print sizes in human-readable units. |
-s | Print the size of each file in bytes. |
--du | Report each directory's total size. |
-p | Print permissions for each entry. |
-u | Print the owner of each entry. |
-D | Print the modification date of each entry. |
-t | Sort by modification time. |
-F | Append / to directories, * to executables, like ls -F. |
-J | Write the tree as JSON. |
-X | Write the tree as XML. |
-l | Follow symlinks to directories. |
-o FILE | Write the output to FILE. |
--charset CHARSET | Use CHARSET for the drawing characters, e.g. ascii. |
--dirsfirst | List directories before files. |
--gitignore | Skip files that .gitignore files exclude. |
--noreport | Omit the file and directory count at the end. |