简体   繁体   中英

Linux command to print directory structure in the form of a tree

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, eg,

folder1
   a.txt
   b.txt
folder2
   folder3

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.

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 , eg in /var/cache/ :

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

Source

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.

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/" 

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

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

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 tree s 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

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.

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

The best answer is, of course, tree. But, to improve on other answers that rely on grepping the output of ls -R , here is a shell script that uses awk to print a tree of subdirectories. First, an example of output:

.
└── matching
    ├── bib
    ├── data
    │   └── source
    │       └── html
    ├── data
    │   └── plots
    ├── method
    │   ├── info
    │   └── soft
    │       ├── imgs
    │       │   ├── ascii
    │       │   └── symbol
    │       └── js
    └── ms

Then, the code:

ls -qLR 2>/dev/null \
| grep '^./' \
| sed -e 's,:$,,' \
| awk '
    function tip(new) { stem = substr(stem, 1, length(stem) - 4) new }
    {
        path[NR] = $0
    }
    END {
        elbow = "└── "; pipe = "│   "; tee = "├── "; blank = "    "
        none = ""
        #
        # Model each stem on the previous one, going bottom up.
        for (row = NR; row > 0; row--) {
            #
            # gsub: count (and clean) all slash-ending components; hence,
            # reduce path to its last component.
            growth = gsub(/[^/]+\//, "", path[row]) - slashes
            if (growth == 0) {
                tip(tee)
            }
            else if (growth > 0) {
                if (stem) tip(pipe) # if...: stem is empty at first!
                for (d = 1; d < growth; d++) stem = stem blank
                stem = stem elbow
            }
            else {
                tip(none)
                below = substr(stem, length(stem) - 4, 4)
                if (below == blank) tip(elbow); else tip(tee)
            }
            path[row] = stem path[row]
            slashes += growth
        }
        root = "."; print root
        for (row = 1; row <= NR; row++) print path[row]
    }
'

The code gives better-looking results than other solutions because in a tree of subdirectories, the decorations in any branch depend on the branches below it. Hence, we need to process the output of ls -R in reverse order, from the last line to the first.

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;
}}'

Combining and extending existing answers into t shell function

t() {
  find -E "${1:-.}" -maxdepth "${2:-3}" \
    -not -regex ".*\/((.idea|.git|.venv|node_modules|venv)\/.*|.DS_Store)" \
  | sort | sed \
    -e "s/[^-][^\/]*\// ├ /g" \
    -e "s/├ \//├ /g" \
    -e "s/├  ├/│  ├/g" \
    -e "s/├  ├/│  ├/g" \
    -e "s/├  │/│  │/g" \
    -e '$s/├/└/'
}

Works on Mac:

$ t
.
 ├ src
 │  ├ .idea
 │  ├ plugins
 │  │  ├ .flake8
 │  │  ├ .git
 │  │  ├ .github
 │  │  ├ .gitignore
 │  │  ├ .pre-commit-config.yaml
 │  │  ├ .python-version
 │  │  ├ Makefile
 │  │  ├ README.md
 │  │  ├ buildspecs
 │  │  ├ cicd
 │  │  ├ cicd.py
 │  │  ├ docker
 │  │  ├ packages
 │  │  ├ plugin_template
 │  │  ├ plugins
 │  │  ├ scripts
 │  │  └ venv


$ t . 2
.
 ├ src
 │  ├ .idea
 │  └ plugins


$ t src/plugins/ | more
 │  ├
 │  ├ .flake8
 │  ├ .git
 │  ├ .github
 │  │  ├ pull_request_template.md
 │  ├ .gitignore
 │  ├ .pre-commit-config.yaml
 │  ├ .python-version
 │  ├ Makefile
 │  ├ README.md
 │  ├ buildspecs
 │  │  ├ test-and-deploy.yml
 │  ├ cicd
:

| more | more can be put at the end of the function for convenience.

是否可以使用递归但将其限制为3个级别?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM