Skip to content

Instantly share code, notes, and snippets.

@nreckart
Created September 18, 2009 19:46
Show Gist options
  • Save nreckart/189253 to your computer and use it in GitHub Desktop.
Save nreckart/189253 to your computer and use it in GitHub Desktop.
lstree is a bash shell script that outputs a recursive directory file listing in a tree type representation.
#!/bin/bash
######################################################################
#
# lstree
#
# Author: Nathan Reckart
#
# Version Date Edited By
# 1.0 9/6/2007 nreckart
# 1.1 9/18/2007 nreckart
# 1.2 9/27/2007 nreckart
# 1.3 7/6/2009 nreckart
#
# Description:
#
# This script will output a recursive directory file listing in a
# tree type representation. It's sort of a more readable version
# of 'ls -R'
#
######################################################################
SCRIPTNAME=${0##*/}
USAGE="Usage: $SCRIPTNAME [OPTIONS]... [DIRECTORY]"
VERSION="1.3"
VERSIONDATE="7/7/2009"
DEBUG=0
DIRONLY=0
SHOWHIDDEN=0
FOLLOWSYMLINKS=0
INDENTSTEP=4
INDENTWITH=" "
INCLUDE_PATTERN=
EXCLUDE_PATTERN=
MAXDEPTH=10
LONGFILENAMES=0
function version() {
cat <<EOF
$SCRIPTNAME $VERSION ($VERSIONDATE)
Written by Nathan Reckart (nreckart AT gmail DOT com)
EOF
}
function usage() {
cat <<EOF
$USAGE
Try '$SCRIPTNAME -h' for more information.
EOF
}
function help() {
cat <<EOF
lstree $VERSION
$USAGE
Recursively list the files and subdirectories of DIRECTORY (the
current directory by default) in a tree like representation.
-a | --all
Show hidden files (those that start with .)
-c | --indent-with STRING
The string to be used to fill for indentation
(Default = blank space)
-d | --directories
Hide files and only list directories
-D | --debug
Turn ON debugging
-h | --help
Display this help message
-l | --symlinks
Follow symbolic links
-L | --long-filenames
Print the full logical path for files and directories
-m | --max-depth INTEGER
Set the maximum sub directory depth (Default = 10)
-p | --include PATTERN
Only show files that match INCLUDE_PATTERN
-P | --exclude PATTERN
Files AND directories matching this pattern will be excluded
-s | --indend-size INTEGER
The number of times to apply -c for each indented level
(Default = 4)
-V | --version
Display the script version information
EOF
exit
}
function getOptionArg() {
OPTION=$1
shift
OPTIONARG=$1
if [[ -n $OPTIONARG && -n $(echo $OPTIONARG | grep "^-") ]] ; then
echo "$SCRIPTNAME: ERROR - invalid option argument ($OPTIONARG) for $OPTION"
exit 1
fi
}
function debugEcho() {
local msg=$1
[ $DEBUG != 0 ] && echo -e $msg
}
function fillIndent() {
INDENTSTR=
for ((i=0; i<$1; i+=1)) ; do
INDENTSTR="${INDENTSTR}${INDENTWITH}"
done
}
function printFilename() {
# If the LONGFILENAMES flag is set, append the filename to the current directory and print
if [ $LONGFILENAMES == 1 ]; then
pwd=$(pwd)
echo ${pwd}/$1
else
printf "%b%s %s\n" "$INDENTSTR " "$1"
fi
}
# This recursive function traverses a directory tree and outputs
# directory and file names.
function printDirContents() {
cd $1
# We just stepped down a level.
((curDepth += 1))
for file in $(eval $lsCommand)
do
specialMsg=
fillIndent $2
if [ -d $file ] ; then
# We're working with a directory.
[ $DEBUG == 1 ] && specialMsg="(Depth = $curDepth)"
[ -L $file ] && specialMsg="$specialMsg (sym link)"
printFilename "$file/ $specialMsg"
if (( curDepth == MAXDEPTH )) ; then
echo -e "$INDENTSTR*** Maximum depth ($MAXDEPTH) reached ***"
fi
# If the maximum depth hasn't yet been acquired, recurse into the directory.
if (( curDepth <= MAXDEPTH )) ; then
# We don't want to follow symbolic links unless the flag is set.
if [[ ! -L $file || $FOLLOWSYMLINKS == 1 ]] ; then
printDirContents $file $(($2 + $INDENTSTEP))
cd ..
# We just stepped up a level.
((curDepth -= 1))
fi
fi
elif [ $DIRONLY == 0 ] ; then
# We're working with a file
# Filter the file name with the INCLUDE_PATTERN
[ $INCLUDE_PATTERN ] && file=$(echo $file | grep "$INCLUDE_PATTERN")
if [[ -n $file ]] ; then
printFilename $file
fi
fi
done
}
# Process any command line arguments
while test $# -gt 0
do
# Break out of loop on the first non option argument
[[ -z $(echo $1 | grep "^-") ]] && break
case "$1" in
-a | --all)
SHOWHIDDEN=1;; # Set the flag to show hidden files (files starting with .)
-c | --indent-with)
getOptionArg $*;shift
INDENTWITH=$OPTIONARG;; # Set the string used to indent each line
-d | --directories)
DIRONLY=1;; # Set the flag to only output directories and suppress file names
-D | --debug)
DEBUG=1;; # Turn debugging ON
-h | --help)
help;; # Display the help message
-l | --symlinks)
FOLLOWSYMLINKS=1;; # Set the flag to follow symbolic links
-L | --long-filenames)
LONGFILENAMES=1 # Display the full path to each file instead of just the file name
INDENTWITH=
INDENTSTEP=0
;;
-m | --max-depth)
getOptionArg $*;shift
MAXDEPTH=$OPTIONARG;; # Set the maximum sub directory depth for recursion
-p | --include)
sgetOptionArg $*;shift
INCLUDE_PATTERN=$OPTIONARG;; # Set the pattern to match file names to be displayed
-P | --exclude)
getOptionArg $*;shift
EXCLUDE_PATTERN=$OPTIONARG;; # Set the patter to match file AND directory names to NOT be displayed
-s | --indent-size)
getOptionArg $*;shift
INDENTSTEP=$OPTIONARG;; # Set the number of times the INDENTWITH string for each file hierarchy level
-V | --version)
version; exit;; # Display the script version info
*) usage; exit 1;;
esac
# Get the next argument
shift
done
# Ignore the indentation options if LONGFILENAMES is set
if [ $LONGFILENAMES == 1 ] ; then
INDENTSTEP=0
INDENTWITH=
fi
# Get the directory, if specified.
DIR=$1; shift
# If no directory is specified, default to the current directory.
[ -z $DIR ] && DIR=.
# Verify that the directory really is a directory.
[ ! -d $DIR ] && echo -e "$DIR is not a valid directory." && usage && exit 1
# Kickoff the recursive function to do all the work.
typeset -i curDepth
typeset -i MAXDEPTH
curDepth=0
# Build the filter that will be used to exclude files AND directories that
# match the EXCLUDE_PATTERN
excludeFileFilterCommand=
if [ $EXCLUDE_PATTERN ] ; then
excludeFileFilterCommand=" | grep -v '$EXCLUDE_PATTERN'"
fi
# Set the ls command that will be used to get a directory listing.
if [ $SHOWHIDDEN != 0 ] ; then
lsCommand="ls -A $excludeFileFilterCommand"
else
lsCommand="ls $excludeFileFilterCommand"
fi
printDirContents $DIR 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment