565
votes

Is there any linux command that I can call from a Bash script that will print the directory structure in the form of a tree, e.g.,

folder1
   a.txt
   b.txt
folder2
   folder3
9
Just run find. Or find . -not -path '*/\.*' to hide files and folders starting with .. If you want to have output with spaces, as in the question, use it with this "find prettifier" script: find . -not -path '*/\.*' | python -c "import sys as s;s.a=[];[setattr(s,'a',list(filter(lambda p: c.startswith(p+'/'),s.a)))or (s.stdout.write(' '*len(s.a)+c[len(s.a[-1])+1 if s.a else 0:])or True) and s.a.append(c[:-1]) for c in s.stdin]"user
Shouldn't such questions get migrated to SuperUser rather than closed ?Balmipour
i dont think this question deserves to be closed as "off topic". The tags seem to be right.Sanket Berde
The policy of closing questions without migrating is harmful to both stackoverflow and human knowledge in general. In the last 3 days, every single questions I googled and came across was closed for similar reasoning, and no more activity was able to happen. This means no one can update it, no one can give a better answer, and it makes stackoverflow look shortsighted or elitist. Stackoverflow should consider requiring a migration when a topic is found to have these conditions.Nay
I agree with @NickYeates I am here in late September of 2017 still finding answers to this same question. Think long term when we design these question and answer policies!Alex

9 Answers

845
votes

Is this what you're looking for tree? It should be in most distributions (maybe as an optional install).

~> tree -d /proc/self/
/proc/self/
|-- attr
|-- cwd -> /proc
|-- fd
|   `-- 3 -> /proc/15589/fd
|-- fdinfo
|-- net
|   |-- dev_snmp6
|   |-- netfilter
|   |-- rpc
|   |   |-- auth.rpcsec.context
|   |   |-- auth.rpcsec.init
|   |   |-- auth.unix.gid
|   |   |-- auth.unix.ip
|   |   |-- nfs4.idtoname
|   |   |-- nfs4.nametoid
|   |   |-- nfsd.export
|   |   `-- nfsd.fh
|   `-- stat
|-- root -> /
`-- task
    `-- 15589
        |-- attr
        |-- cwd -> /proc
        |-- fd
        | `-- 3 -> /proc/15589/task/15589/fd
        |-- fdinfo
        `-- root -> /

27 directories

sample taken from maintainer's web page.

You can add the option -L # where # is replaced by a number, to specify the max recursion depth.

Remove -d to display also files.

361
votes

You can use this one:

ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/   /' -e 's/-/|/'

It will show a graphical representation of the current sub-directories without files in a few seconds, e.g. in /var/cache/:

   .
   |-apache2
   |---mod_cache_disk
   |-apparmor
   |-apt
   |---archives
   |-----partial
   |-apt-xapian-index
   |---index.1
   |-dbconfig-common
   |---backups
   |-debconf

Source

34
votes

This command works to display both folders and files.

find . | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/"

Example output:

.
 |-trace.pcap
 |-parent
 | |-chdir1
 | | |-file1.txt
 | |-chdir2
 | | |-file2.txt
 | | |-file3.sh
 |-tmp
 | |-json-c-0.11-4.el7_0.x86_64.rpm

Source: Comment from @javasheriff here. Its submerged as a comment and posting it as answer helps users spot it easily.

21
votes

To add Hassou's solution to your .bashrc, try:

alias lst='ls -R | grep ":$" | sed -e '"'"'s/:$//'"'"' -e '"'"'s/[^-][^\/]*\//--/g'"'"' -e '"'"'s/^/   /'"'"' -e '"'"'s/-/|/'"'"
16
votes

Since it was a successful comment, I am adding it as an answer:
To print the directory structure in the form of a tree,
WITH FILES

 find . | sed -e "s/[^-][^\/]*\//  |/g" -e "s/|\([^ ]\)/|-\1/" 
10
votes

Since I was not too happy with the output of other (non-tree) answers (see my comment at Hassou's answer), I tried to mimic trees output a bit more.

It's similar to the answer of Robert but the horizontal lines do not all start at the beginning, but where there are supposed to start. Had to use perl though, but in my case, on the system where I don't have tree, perl is available.

ls -aR | grep ":$" | perl -pe 's/:$//;s/[^-][^\/]*\//    /g;s/^    (\S)/└── \1/;s/(^    |    (?= ))/│   /g;s/    (\S)/└── \1/'

Output (shortened):

.
└── fd
└── net
│   └── dev_snmp6
│   └── nfsfs
│   └── rpc
│   │   └── auth.unix.ip
│   └── stat
│   └── vlan
└── ns
└── task
│   └── 1310
│   │   └── net
│   │   │   └── dev_snmp6
│   │   │   └── rpc
│   │   │   │   └── auth.unix.gid
│   │   │   │   └── auth.unix.ip
│   │   │   └── stat
│   │   │   └── vlan
│   │   └── ns

Suggestions to avoid the superfluous vertical lines are welcome :-)

I still like Ben's solution in the comment of Hassou's answer very much, without the (not perfectly correct) lines it's much cleaner. For my use case I additionally removed the global indentation and added the option to also ls hidden files, like so:

ls -aR | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//  /g'

Output (shortened even more):

.
  fd
  net
    dev_snmp6
    nfsfs
    rpc
      auth.unix.ip
    stat
    vlan
  ns
6
votes

I'm prettifying the output of @Hassou's answer with:

ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//──/g' -e 's/─/├/' -e '$s/├/└/'

This is much like the output of tree now:

.
├─pkcs11
├─pki
├───ca-trust
├─────extracted
├───────java
├───────openssl
├───────pem
├─────source
├───────anchors
├─profile.d
└─ssh

You can also make an alias of it:

alias ltree=$'ls -R | grep ":$" | sed -e \'s/:$//\' -e \'s/[^-][^\/]*\//──/g\' -e \'s/─/├/\' -e \'$s/├/└/\''

BTW, tree is not available in some environment, like MinGW. So the alternate is helpful.

4
votes

Adding the below function in bashrc lets you run the command without any arguments which displays the current directory structure and when run with any path as argument, will display the directory structure of that path. This avoids the need to switch to a particular directory before running the command.

function tree() {
    find ${1:-.} | sed -e "s/[^-][^\/]*\//  |/g" -e "s/|\([^ ]\)/|-\1/"
}

This works in gitbash too.

Source: Comment from @javasheriff here

3
votes

You can also use the combination of find and awk commands to print the directory tree. For details, please refer to "How to print a multilevel tree directory structure using the linux find and awk combined commands"

find . -type d | awk -F'/' '{ 
depth=3;
offset=2;
str="|  ";
path="";
if(NF >= 2 && NF < depth + offset) {
    while(offset < NF) {
        path = path "|  ";
        offset ++;
    }
    print path "|-- "$NF;
}}'