There exists a program called tree that recursively prints a graphical tree diagram to the terminal. In the spirit of the Unix philosophy, however, there is another way to print a tree with the basic Unix programs [1].
find | sed 's;[^/]*/;|____;g;s;____|; |;g'
Let us do a short walkthrough of what this command does.
Using find alone yields the full path of every file on each line. Interestingly, it is difficult to recursively print all full paths on single lines with ls, which is why find is used instead. The output format of find is convenient to parse with sed.
$ find . ./run_avg ./run_avg/Makefile ./run_avg/movAvg.c ./run_avg/test.m ./run_avg/ship ./run_avg/ship/Makefile ./run_avg/ship/generate ./run_avg/ship/test.m ./run_avg/ship/moving-average.pdf ./run_avg/ship/sine.png ./run_avg/ship/mine ./run_avg/ship/mine/result1024.csv ./run_avg/ship/mine/result1025.csv ./run_avg/ship/mine/result1000000.csv ./run_avg/ship/mine/result0.csv ./run_avg/ship/mine/result10000.csv ./run_avg/ship/mine/result100.csv ./run_avg/ship/generate.c ./run_avg/moving-average.pdf ./run_avg/sine.png ./run_avg/generate.c ./run_avg/moving-average.odt
Here, we pipe the full paths of all directories under our present working directory into sed, which replaces everything between the first forward slash and the last forward slash with lines depicting the tree.
$ find | sed 's;[^/]*/;|____;g;s;____|; |;g' . |____run_avg | |____Makefile | |____movAvg.c | |____test.m | |____ship | | |____Makefile | | |____generate | | |____test.m | | |____moving-average.pdf | | |____sine.png | | |____mine | | | |____result1024.csv | | | |____result1025.csv | | | |____result1000000.csv | | | |____result0.csv | | | |____result10000.csv | | | |____result100.csv | | |____generate.c | |____moving-average.pdf | |____sine.png | |____generate.c | |____moving-average.odt
Of course, the we can elaborate on this simple command, as demonstrated by the following polished command. In this command, I omit hidden files from the tree by removing lines with hidden files from the output of find. I then sort the lines alphanumerically with sort. The final result is piped into sed to draw the tree.
find | sed '/\/\./d' | sort -d | sed 's;[^/]*/;|___;g;s;___|; |;g'
As with all things Unix, a shell script is usually helpful.
#!/bin/bash # Prints Directory Tree if [ "$1" == "-h" ]; then # show hidden files find | sort -d | sed 's;[^/]*/;|____;g;s;____|; |;g' elif [ "$1" == "-m" ]; then # expect manual input pipe sed 's;[^/]*/;|____;g;s;____|; |;g' else find | sed '/\/\./d' | sort -d | sed 's;[^/]*/;|___;g;s;___|; |;g' fi
tree is a properly written program that has all the options you could wish for. It is better that our little command in almost every way, especially in speed. lt is the shell script from before.
$ time lt > /dev/null; time tree > /dev/null real 0m0.613s user 0m0.628s sys 0m0.104s real 0m0.078s user 0m0.056s sys 0m0.020s
The output is almost exactly the same, except for the pretty box characters and the omission of the extra pipe characters indicating directory depth.
$ lt; tree . |___run_avg | |___generate.c | |___Makefile | |___movAvg.c | |___moving-average.odt | |___moving-average.pdf | |___ship | | |___generate | | |___generate.c | | |___Makefile | | |___mine | | | |___result0.csv | | | |___result1000000.csv | | | |___result10000.csv | | | |___result100.csv | | | |___result1024.csv | | | |___result1025.csv | | |___moving-average.pdf | | |___sine.png | | |___test.m | |___sine.png | |___test.m . └── run_avg ├── generate.c ├── Makefile ├── movAvg.c ├── moving-average.odt ├── moving-average.pdf ├── ship │ ├── generate │ ├── generate.c │ ├── Makefile │ ├── mine │ │ ├── result0.csv │ │ ├── result1000000.csv │ │ ├── result10000.csv │ │ ├── result100.csv │ │ ├── result1024.csv │ │ └── result1025.csv │ ├── moving-average.pdf │ ├── sine.png │ └── test.m ├── sine.png └── test.m 3 directories, 19 files
One drawback of the tree command is that it is purpose built and can not do anything else besides drawing directory trees (although it does just that very well). With our simple command we can pipe in more than just a directory list. We can use this to visualize things like dependencies in a C programming project or a simple family tree. A bit of awk should get whatever you need into the single line format that works so well with sed.
Written on the 21st of December in 2014