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
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
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/"
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
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
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;
}}'
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.
A shell function based on this code (with a few options) can be found here: