This post is part of an educational series on building a shell script to graphically display the structure of a directory.
Previously
- We broke down Dem Pilafian’s one line command to display a tree of a directory
- We broke down Dem Pilafian’s script that uses the one line command
- We modified the one line to show files, as well as directories
- We built a recursive function that successfully prints out the graphical tree
- We Optimized the function by passing a string instead of an array
Goals
- Optimize the previously built recursive function.
Pre-requisites
Getting the code
Run the following command:
git clone https://github.com/amayem/shell-tree.git
In any step past step-0
you can get the code by issuing the following command but changing the step number to the appropriate one:
git checkout -f step-1
Step-15 Passing a String without Changing IFS
Last step we solved the problem of passing whitespace as a parameter to a function by changing the IFS. After some more research into the problem, (which resulted in the post about passing whitespace as parameter to a function) I found a way to do it without even having to change the IFS. We just have to use double quotes properly:
listdir()
{
local currentPath=$1 prefix="$2"
local -a currentDir=($(ls $1))
local -i lastIndex=$((${#currentDir[*]} - 1)) index
for ((index=0; index<lastIndex; index++))
do
printf "%s├─%s\n" "$prefix" ${currentDir[$index]}
if [ -d "$currentPath/${currentDir[$index]}" ]; then
listdir "$currentPath/${currentDir[$index]}" "$prefix""│ "
fi
done
if [ $lastIndex -ge 0 ]; then
printf "%s└─%s\n" "$prefix" ${currentDir[$lastIndex]}
if [ -d "$currentPath/${currentDir[$index]}" ]; then
listdir "$currentPath/${currentDir[$index]}" "$prefix"" "
fi
fi
}
listdir $PWD ''
This gives the following:
[ahmed@amayem .git]$ ./../tree.sh
├─COMMIT_EDITMSG
├─HEAD
├─config
├─description
├─hooks
│ ├─applypatch-msg.sample
│ ├─commit-msg.sample
│ ├─post-update.sample
│ ├─pre-applypatch.sample
│ ├─pre-commit.sample
│ ├─pre-push.sample
│ ├─pre-rebase.sample
│ ├─prepare-commit-msg.sample
│ └─update.sample
├─index
├─info
│ └─exclude
├─logs
│ ├─HEAD
│ └─refs
│ ├─heads
│ │ └─master
│ └─remotes
│ └─origin
│ ├─HEAD
│ └─master
├─objects
│ ├─info
│ └─pack
│ ├─pack-5d8c6d23ff13eded7a9d401ff91dae0f7fd6d00d.idx
│ └─pack-5d8c6d23ff13eded7a9d401ff91dae0f7fd6d00d.pack
├─packed-refs
└─refs
├─heads
│ └─master
├─remotes
│ └─origin
│ ├─HEAD
│ └─master
└─tags
Looks good.
Next Steps
- Allow for flags to be used that are compatible with
ls
- Deal with bad input
- Make it a user friendly bash script