ShellTree 2: Analyzing the One Line Implementation Script

This post is part of an educational series on building a shell script to graphically display the structure of a directory.

Previously

  1. We broke down Dem Pilafian’s one line command to display a tree of a directory

The Script

#!/bin/sh
#######################################################
#  UNIX TREE                                          #
#  Version: 2.3                                       #
#  File: ~/apps/tree/tree.sh                          #
#                                                     #
#  Displays Structure of Directory Hierarchy          #
#  -------------------------------------------------  #
#  This tiny script uses "ls", "grep", and "sed"      #
#  in a single command to show the nesting of         #
#  sub-directories.  The setup command for PATH       #
#  works with the Bash shell (the Mac OS X default).  #
#                                                     #
#  Setup:                                             #
#     $ cd ~/apps/tree                                #
#     $ chmod u+x tree.sh                             #
#     $ ln -s ~/apps/tree/tree.sh ~/bin/tree          #
#     $ echo "PATH=~/bin:${PATH}" >> ~/.profile      #
#                                                     #
#  Usage:                                             #
#     $ tree [directory]                              #
#                                                     #
#  Examples:                                          #
#     $ tree                                          #
#     $ tree /etc/opt                                 #
#     $ tree ..                                       #
#                                                     #
#  Public Domain Software -- Free to Use as You Like  #
#  http://www.centerkey.com/tree  -  By Dem Pilafian  #
#######################################################

echo
if [ "$1" != "" ]  #if parameter exists, use as base folder
   then cd "$1"
   fi
pwd
ls -R | grep ":$" |   
   sed -e 's/:$//' -e 's/[^-][^/]*//--/g' -e 's/^/   /' -e 's/-/|/'
# 1st sed: remove colons
# 2nd sed: replace higher level folder names with dashes
# 3rd sed: indent graph three spaces
# 4th sed: replace first dash with a vertical bar
if [ `ls -F -1 | grep "/" | wc -l` = 0 ]   # check if no folders
   then echo "   -> no sub-directories"
   fi
echo
exit

Setup

Directory setup

Please check the first post on the tree command to see our directory setup.

Script setup

I will not add the script to my path as of yet, as we are just testing right now. First let’s add it to where we are testing. Open up vi and paste. Check here to see how to paste in vi. Exit insert mode and save the file.

[ahmed@amayem .git]$ vi test.sh
[ahmed@amayem .git]$ ./test.sh
-bash: ./test.sh: Permission denied
[ahmed@amayem .git]$ chmod +x test.sh 
[ahmed@amayem .git]$ ./test.sh

/home/ahmed/test/.git
   .
   |-branches
   |-hooks
   |-info
   |-objects
   |---info
   |---pack
   |-refs
   |---heads
   |---tags

Looks like it’s working.

Script Breakdown

echo

We are printing a new line.

if [ "$1" != "" ]  #if parameter exists, use as base folder
   then cd "$1"
   fi

The $1 variable indicates the first command line argument. For example if we said tree ~ then $1 would equal ~. So basically we are checking if an argument was given. If one was given then go to it.

pwd

The working directory is printed.

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

We analyzed this in our previous post.

if [ `ls -F -1 | grep "/" | wc -l` = 0 ]   # check if no folders
   then echo "   -> no sub-directories"
   fi

Let’s check the man page for ls:

-F, --classify
          append indicator (one of */=>@|) to entries

and

-1     list one file per line

Let’s see what we get when we try it by itself:

[ahmed@amayem .git]$ ls -F -1
branches/
config
description
HEAD
hooks/
info/
objects/
refs/
test.sh*

So it added a slash, /, to the ends of directories, nothing to the end of normal files, and a star, *, to the end of executables.

grep "/"

The output from the previous ls command is piped into this grep command which singles out the directories.

wc -l` = 0

Let’s check the man page of wc:

wc - print newline, word, and byte counts for each file

and

-l, --lines
          print the newline counts

So we are counting how many directories we have in the working directory. If that number is zero then print out, " -> no sub-directories".

echo

Print out a new line.

Next steps

  1. Modifying the one line command to show files, as well as directories
  2. Building a new recursive script that looks better and has more functionality

References

  1. Dem Pilafian on centerkey

Ahmed Amayem has written 90 articles

A Web Application Developer Entrepreneur.