Skip to content

Instantly share code, notes, and snippets.

@hunandy14
Created May 29, 2024 10:11
Show Gist options
  • Save hunandy14/dbdd7f5114a50b74c825772ba3125514 to your computer and use it in GitHub Desktop.
Save hunandy14/dbdd7f5114a50b74c825772ba3125514 to your computer and use it in GitHub Desktop.
This script shows the directory tree, color-codes files and folders, and optionally displays file sizes and hidden files.
#!/bin/bash
# This script displays the directory tree structure, color-codes files and folders,
# and optionally shows file sizes and hidden files.
# Usage:
# tree.sh [-a] [-s] <directory>
# -a Show all files including hidden files
# -s Show file sizes
# Detailed Usage:
# - `-a` or `--all`: Show all files, including hidden files.
# - `-s` or `--size`: Display the size of each file.
# Examples:
# 1. Show the directory structure, including hidden files and file sizes:
# tree.sh -a -s testdir/
#
# 2. Show the directory structure without hidden files and file sizes:
# tree.sh testdir/
#
# 3. Show the directory structure with file sizes but without hidden files:
# tree.sh -s testdir/
# Function to format file size
function format_size() {
local size=$1
local units=("B" "KB" "MB" "GB" "TB" "PB")
local unit_index=0
local decimal_places=3
while (( $(echo "$size >= 1024" | bc -l) )); do
size=$(echo "scale=$decimal_places; $size / 1024" | bc)
unit_index=$(( unit_index + 1 ))
done
size=$(echo $size | awk '{printf "%.'$decimal_places'f", $0}')
size=$(echo $size | sed 's/\.0*$//;s/\.\([0-9]*[1-9]\)0*$/.\1/')
echo "$size ${units[$unit_index]}"
}
# Function to print the item name with color based on file type
function print_item() {
local item_name=$1
shift
local description=""
local item_type=""
while [ $# -gt 0 ]; do
case $1 in
--description=*|-d)
if [[ "$1" == "--description="* ]]; then
description="${1#*=}"
shift
else
description="$2"
shift 2
fi
;;
--type=*|-t)
if [[ "$1" == "--type="* ]]; then
item_type="${1#*=}"
shift
else
item_type="$2"
shift 2
fi
;;
*)
echo "Unknown argument: $1"
return 1
;;
esac
done
local base_name=$(basename "$item_name")
local extension="${base_name##*.}"
local COLOR_RESET="\033[0m"
local COLOR_FOLDER="\033[1;34m" # Blue color for folders
local COLOR_EXEC="\033[1;32m" # Green color for executable files
local COLOR_LINK="\033[1;36m" # Cyan color for links
local COLOR_COMPRESSED="\033[1;31m" # Red color for compressed files
local COLOR_IMAGE="\033[1;35m" # Magenta color for image files
local COLOR_VIDEO="\033[1;33m" # Yellow color for video files
local COLOR_AUDIO="\033[1;36m" # Cyan color for audio files
local COLOR_FIFO="\033[1;33;40m" # Yellow background black text for FIFO
local COLOR_DEVICE="\033[1;34;43m" # Yellow background blue text for devices
local COLOR_SUID="\033[1;37;41m" # White background red text for SUID files
local COLOR_SGID="\033[1;30;43m" # Black background yellow text for SGID files
local COLOR_STICKY="\033[1;37;44m" # Blue background white text for sticky directories
local COLOR_OW="\033[1;30;42m" # Green background black text for other-writable directories
local COLOR_DEFAULT="\033[0m" # Default color for other files
local colored_name
if [ "$item_type" = "folder" ]; then
colored_name="${COLOR_FOLDER}${base_name}/${COLOR_RESET}"
else
if [ -x "$item_name" ]; then
colored_name="${COLOR_EXEC}${base_name}${COLOR_RESET}"
elif [ -L "$item_name" ]; then
colored_name="${COLOR_LINK}${base_name}${COLOR_RESET}"
elif [[ "$extension" =~ ^(zip|tar|gz|bz2|xz|7z|rar)$ ]]; then
colored_name="${COLOR_COMPRESSED}${base_name}${COLOR_RESET}"
elif [[ "$extension" =~ ^(jpg|jpeg|png|gif|bmp|tiff|svg|ico)$ ]]; then
colored_name="${COLOR_IMAGE}${base_name}${COLOR_RESET}"
elif [[ "$extension" =~ ^(mp4|mkv|avi|mov|flv|wmv|webm)$ ]]; then
colored_name="${COLOR_VIDEO}${base_name}${COLOR_RESET}"
elif [[ "$extension" =~ ^(mp3|wav|ogg|flac|aac|m4a)$ ]]; then
colored_name="${COLOR_AUDIO}${base_name}${COLOR_RESET}"
elif [ -p "$item_name" ]; then
colored_name="${COLOR_FIFO}${base_name}${COLOR_RESET}"
elif [ -b "$item_name" ] || [ -c "$item_name" ]; then
colored_name="${COLOR_DEVICE}${base_name}${COLOR_RESET}"
elif [ -u "$item_name" ]; then
colored_name="${COLOR_SUID}${base_name}${COLOR_RESET}"
elif [ -g "$item_name" ]; then
colored_name="${COLOR_SGID}${base_name}${COLOR_RESET}"
elif [ -k "$item_name" ]; then
colored_name="${COLOR_STICKY}${base_name}${COLOR_RESET}"
elif [ -w "$item_name" ] && [ -d "$item_name" ]; then
colored_name="${COLOR_OW}${base_name}${COLOR_RESET}"
else
colored_name="${COLOR_DEFAULT}${base_name}${COLOR_RESET}"
fi
fi
if [ -n "$description" ]; then
echo -e "${colored_name} ${description}"
else
echo -e "${colored_name}"
fi
}
# Function to recursively print the directory tree structure
function print_tree() {
local directory=$1
local prefix=$2
local files=()
if $show_hidden; then
files=("$directory"/{.,}*)
else
files=("$directory"/*)
fi
# Filter out non-existent files and directories (handle empty directories)
files=(${files[@]/*\*/})
local last_index=$((${#files[@]} - 1))
for i in "${!files[@]}"; do
local file="${files[$i]}"
local basename=$(basename "$file")
local new_prefix="$prefix"
if [ "$basename" == "." ] || [ "$basename" == ".." ]; then
continue
fi
if [ $i -eq $last_index ]; then
echo -n "${prefix}└── "
new_prefix="$prefix "
else
echo -n "${prefix}├── "
new_prefix="$prefix│ "
fi
if [ -d "$file" ]; then
dir_count=$((dir_count + 1))
print_item "$file" -t "folder"
print_tree "$file" "$new_prefix"
else
if $show_size; then
local size=$(stat -c %s "$file")
local formatted_size=$(format_size $size)
print_item "$file" -d "($formatted_size)" -t "file"
else
print_item "$file" -t "file"
fi
file_count=$((file_count + 1))
fi
done
}
# Default options
show_hidden=false
show_size=false
dir_count=0
file_count=0
# Parse options
while getopts "as" opt; do
case $opt in
a)
show_hidden=true
;;
s)
show_size=true
;;
*)
echo "Usage: $0 [-a] [-s] <directory>"
echo " -a Show all files including hidden files"
echo " -s Show file sizes"
exit 1
;;
esac
done
shift $((OPTIND - 1))
# Check if a directory is provided as an argument
if [ -z "$1" ]; then
echo "Usage: $0 [-a] [-s] <directory>"
echo " -a Show all files including hidden files"
echo " -s Show file sizes"
exit 1
fi
# Remove trailing slash from the directory if it exists
directory=$(echo "$1" | sed 's:/*$::')
# Print the initial directory with color
print_item "$directory" -t "folder"
print_tree "$directory" ""
# Print the summary
echo -e "\n$dir_count directories, $file_count files"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment