Created
September 18, 2009 19:46
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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