ShellTree 6: Further Optimization by Removing Changes to IFS

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
  2. We broke down Dem Pilafian’s script that uses the one line command
  3. We modified the one line to show files, as well as directories
  4. We built a recursive function that successfully prints out the graphical tree
  5. We Optimized the function by passing a string instead of an array

Goals

  1. Optimize the previously built recursive function.

Pre-requisites

  1. Understanding how to pass whitespace to functions

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

  1. Allow for flags to be used that are compatible with ls
  2. Deal with bad input
  3. Make it a user friendly bash script

References

  1. How to pass whitespace to functions

Ahmed Amayem has written 90 articles

A Web Application Developer Entrepreneur.